In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.
In functional languages such as Scheme and Haskell, functions are first-class. This means that we can pass functions as arguments to other functions, assign functions to variables, and have them as return values just like any other primitive data types such as integers and strings.
In Python, functions are likewise treated as first-class citizens. In fact, the language provides syntactic sugar known as decorators which makes wrapping functions and function transformations even easier.
An example in Python:
In the code above, we have defined a function italicize which accepts a function sayHi, and returns a new function called wrapper which is then assigned to a variable italicHi.
Decorators are effectively function wrappers that are run when the python interpreter loads the function, and can modify what the function receives and returns.
We can rewrite the above code using the decorator pattern:
A decorator is a function that expects another function as a parameter. As you can see, the following two function definitions are equivalent:
We can also chain decorators, effectively nesting them:
By this point, you may be wondering: what can I use decorators for? You can use them to extends several functions with the same code without rewriting it every time, for DRY’s (Don’t Repeat Yourself!) sake. A real-life decorator in a Django project (from the Django source):
Say we have a bunch of views we want to only be accessible to a site’s admins. Instead of rewriting logic that checks for admin privileges for each of the views, we can simply define a decorator for admin access once, and decorate the relevant views with @admin_required. You can also parameterize your decorators:
In short, decorators let you execute code before and after the function they decorate. Python’s decorator pattern is a great example of DRY. It helps you abstract away the repeating parts of your code into a function wrapper you can decorate other functions with.
📬 Get updates straight to your inbox!
Subscribe to my newsletter to make sure you don't miss anything.