Reader small image

You're reading from  Advanced Python Programming - Second Edition

Product typeBook
Published inMar 2022
PublisherPackt
ISBN-139781801814010
Edition2nd Edition
Right arrow
Author (1)
Quan Nguyen
Quan Nguyen
author image
Quan Nguyen

Quan Nguyen is a Python programmer and machine learning enthusiast. He is interested in solving decision-making problems under uncertainty. Quan has authored several books on Python programming and scientific computing. He is currently pursuing a Ph.D. degree in computer science at Washington University in St. Louis, researching Bayesian methods in machine learning.
Read more about Quan Nguyen

Right arrow

Chapter 20: The Decorator Pattern

As we saw in the previous chapter, using an adapter, the first structural design pattern, you can adapt an object implementing a given interface to implement another interface. This is called interface adaptation and includes the kinds of patterns that encourage composition over inheritance, and it could bring benefits when you have to maintain a large codebase.

A second interesting structural pattern to learn about is the decorator pattern, which allows us to add responsibilities to an object dynamically and transparently (without affecting other objects); this will be the topic of this chapter. Throughout our discussions, we will learn more about a specific usage of this design pattern: memoization.

We will discuss the following topics:

  • Introducing the decorator pattern
  • Real-world examples
  • Use cases
  • Implementation

Technical requirements

The code files for this chapter can be accessed through this link: https://github.com/PacktPublishing/Advanced-Python-Programming-Second-Edition/tree/main/Chapter20.

Introducing the decorator pattern

As Python developers, we can write decorators in a Pythonic way (meaning using the language's features), thanks to the built-in decorator feature (https://docs.python.org/3/reference/compound_stmts.html#function). What exactly is this feature? A Python decorator is a callable (function, method, or class) that gets a function object, func_in, as input and returns another function object, func_out. It is a commonly used technique for extending the behavior of a function, method, or class.

But this feature should not be completely new to you. We have already seen how to use the built-in property decorator, which makes a method appear as a variable in both Chapter 16, The Factory Pattern, and Chapter 17, The Builder Pattern. There are also several other useful built-in decorators in Python. In the Implementation section of this chapter, we will learn how to implement and use our own decorators.

Note that there is no one-to-one relationship between...

Real-world examples

The decorator pattern is generally used for extending the functionality of an object. In everyday life, examples of functionality extensions are adding a holder stand to a phone or using different camera lenses.

In the Django framework, which uses decorators a lot, we have the View decorators, which can be used for the following (j.mp/djangodec):

  • Restricting access to views based on the HTTP request
  • Controlling the caching behavior on specific views
  • Controlling compression on a per-view basis
  • Controlling caching based on specific HTTP request headers

Both the Pyramid framework and the Zope application server also use decorators to achieve various goals, such as the following:

  • Registering a function as an event subscriber
  • Protecting a method with a specific permission
  • Implementing the adapter pattern

To be more concrete, we will iterate the specific use cases of the design pattern in the next section.

Use cases

The decorator pattern shines when used for implementing cross-cutting concerns (j.mp/wikicrosscut). Examples of cross-cutting concerns are as follows:

  • Data validation
  • Caching
  • Logging
  • Monitoring
  • Debugging
  • Business rules
  • Encryption

In general, all parts of an application that are generic and can be applied to many different parts of it are considered to be cross-cutting concerns.

Another popular example of using the decorator pattern is graphical user interface (GUI) toolkits. In a GUI toolkit, we want to be able to add features such as borders, shadows, colors, and scrolling to individual components/widgets.

Now, let's move on to the implementation part of the chapter, in which we will see how the decorator pattern helps with memoization.

Implementation

Python decorators are generic and very powerful. You can find many examples of how they can be used in the decorator library of python.org (j.mp/pydeclib). In this section, we will see how we can implement a memoization decorator (j.mp/memoi). All recursive functions can benefit from memoization, so let's try a function, number_sum(), that returns the sum of the first n numbers. Note that this function is already available in the math module as fsum(), but let's pretend it is not.

First, let's look at the naive implementation (the number_sum_naive.py file):

def number_sum(n): 
    '''Returns the sum of the first n numbers''' 
    assert(n >= 0), 'n must be >= 0' 
    
    if n == 0:
        return 0
    else:
        return...

Summary

This chapter covered the decorator pattern and its relationship to the Python programming language. We used the decorator pattern conveniently to extend the behavior of an object without using inheritance. Python, with its built-in decorator feature, extends the decorator concept even more, by allowing us to extend the behavior of any callable (function, method, or class) without using inheritance or composition.

We have seen a few examples of real-world objects that are decorated, such as cameras. From a software point of view, both Django and Pyramid use decorators to achieve different goals, such as controlling HTTP compression and caching.

The decorator pattern is a great solution for implementing cross-cutting concerns because they are generic and do not fit well into the OOP paradigm. We mentioned several categories of cross-cutting concerns in the Use cases section. In fact, in the Implementation section, a cross-cutting concern was demonstrated: memoization. We...

Questions

  1. What is the main motivation for the decorator pattern?
  2. Why is the decorator pattern particularly relevant in Python?
  3. How does the decorator pattern help with memoization?
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Advanced Python Programming - Second Edition
Published in: Mar 2022Publisher: PacktISBN-13: 9781801814010
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Quan Nguyen

Quan Nguyen is a Python programmer and machine learning enthusiast. He is interested in solving decision-making problems under uncertainty. Quan has authored several books on Python programming and scientific computing. He is currently pursuing a Ph.D. degree in computer science at Washington University in St. Louis, researching Bayesian methods in machine learning.
Read more about Quan Nguyen