Decorators in Python

In programming, decorator is a design pattern that adds additional responsibilities to an object dynamically. In Python, a function is the first-order object. So, a decorator in Python adds additional responsibilities/functionalities to a function dynamically without modifying a function.

In Python, a function can be passed as an argument to another function. It is also possible to define a function inside another function, and a function can return another function.

So, a decorator in Python is a function that receives another function as an argument. The behavior of the argument function is extended by the decorator without actually modifying it. The decorator function can be applied over a function using the @decorator syntax.

Let's understand the decorator in Python step-by-step.

Consider that we have the greet() function, as shown below.

Example: A Function
def greet():
	print('Hello! ', end='')

Now, we can extend the above function's functionality without modifying it by passing it to another function, as shown below.

Example: A Function with Argument
def mydecorator(fn):
	fn()
	print('How are you?')

Above, the mydecorator() function takes a function as an argument. It calls the argument function and also prints some additional things. Thus, it extends the functionality of the greet() function without modifying it. However, it is not the actual decorator.

Example: Calling Function in Python Shell
>>> mydecorator(greet)
Hello! How are you?

The mydecorator() is not a decorator in Python. The decorator in Python can be defined over any appropriate function using the @decorator_function_name syntax to extend the functionality of the underlying function.

The following defines the decorator for the above greet() function.

Example: A Decorator Function
def mydecorator(fn):
    def inner_function():        
        fn()
        print('How are you?')
    return inner_function

The mydecorator() function is the decorator function that takes a function (any function that does not take any argument) as an argument. The inner function inner_function() can access the outer function's argument, so it executes some code before or after to extend the functionality before calling the argument function. The mydecorator function returns an inner function.

Now, we can use mydecorator as a decorator to apply over a function that does not take any argument, as shown below.

Example: Applying Decorator
@mydecorator
def greet():
	print('Hello! ', end='')

Now, calling the above greet() function will give the following output.

Example: Calling a Decorated Function
>>> greet()
Hello! How are you?

The mydecorator can be applied to any function that does not require any argument. For example:

Example: Applying Decorator
@mydecorator
def dosomething():
	print('I am doing something.', end='')
Example: Calling Decorated Function in Python Shell
>>> dosomething()
I am doing something. How are you?

The typical decorator function will look like below.

Decorator Function Syntax
def mydecoratorfunction(some_function): # decorator function
    def inner_function(): 
        # write code to extend the behavior of some_function()
        some_function() # call some_function
        # write code to extend the behavior of some_function()
    return inner_function # return a wrapper function

Built-in Decorators

Python library contains many built-in decorators as a shortcut of defining properties, class method, static methods, etc.

Decorator Description
@property Declares a method as a property's setter or getter methods.
@classmethod Declares a method as a class's method that can be called using the class name.
@staticmethod Declares a method as a static method.

Learn about the built-in decorator @property next.

Want to check how much you know Python?