Python

Python Decorators

Python Decorators

This page covers Python Decorators.

Similar to the idea of a gift decoration, Python decorators wrap functions.

The concept of decorators wraps one function over another. In other words, it transform functions by adding more functionality.

This method was designed to replace the older transformative approach, which is less efficient.

Before exploring decorators, let’s understand functions better.

First-class objects

In Python, functions are first-class objects.

If you are not familiar with Python functions, please check here first.

First-class functions refer to functions that can be:

  • stored in variables
  • defined in other functions (nested)
  • passed as arguments
  • returned by other functions

Let’s briefly explore the above first-class function characteristics.

Normal functions

def func(text):
    print(text)

func("Hello, World!")

# Output: Hello, World!

Function stored in a variable

def func(text):
    print(text)

someVariable = func
someVariable("Hello, World!")

# Output: Hello, World! 

A function defined in another function (nested functions)

def func(text):
    print("Start")

    def wrapper(text):
        print(text)
        print("End")

    wrapper(text)

func("Hello, World!")

# Start
# Hello, World!
# End

Function passed as an argument

def func():
    print("Hello, world!")

def another_func(func):
    func()

another_func(func)

# Output: Hello, world!

A function returned by another function

def func():
    print("Hello world, from the function.")
    
    def inside_func():
        print("Hello world, from the inner function.")
        return inside_func

    return inside_func()

func()

# Hello world, from the function.
# Hello world, from the inner function.

The above is a concise explanation of the characteristics of a first-class function. Now, we can dive into the concept of decorators.

Decorators

The operation behind decorators is transforming functions.

Applying a decorator over a function allows a redesign of that function. As such, new functionalities can be added.

To apply a decorator, use the “@” symbol.

Let’s create a simple decorator, which can be used at any time later on. The decorator adds the message “Adding more..”.

def decorator(func):
    def wrapper():
        print("Adding more..")
        func()
    return wrapper

Now, we create a simple function.

def some_text():
    print("Hello, world!")

some_text()
# Output: Hello, world!

The function is very basic and has one functionality, to print “Hello, world!”. We can now add the functionality of the decorator.

Let’s apply the decorator (with @) and call the function again. Decorators always go above the function.

@decorator
def some_text():
    print("Hello, world!")

some_text()
# Adding more..
# Hello, world!

We can apply the same decorator to multiple functions as well as multiple decorators to one function.

Below is an example. We create a second function, displaying the length of a list of numbers. In addition, we create a second decorator (decorator_2) and apply both decorators to both functions.

def decorator(func):
    def wrapper():
        print("Adding more..")
        func()
    return wrapper

def decorator_2(func):
    def wrapper():
        print("Adding even more..")
        func()
    return wrapper

@decorator
@decorator_2
def some_text():
    print("Hello, world!")

@decorator
@decorator_2
def some_numbers():
    numbers = [2, 7, 12, 1, 7]
    print(len(numbers))


some_text()
some_numbers()

Let’s check the outcome.

Adding more..
Adding even more..
Hello, world!
Adding more..
Adding even more..
5

Decorators with arguments (*args & **kwargs)

We can also pass arguments through decorators.

This can happen through the use arbitrary arguments (*args) and keyword arbitrary arguments (**kwargs).

For more here.

Let’s create an example of a decorator with some arguments.

def decorator(func):
    def wrapper(*args, **kwargs):
        print("Adding", args)
        print("Adding", kwargs)
        func()
    return wrapper

@decorator
def some_text():
    print("Hello, world!")

some_text(1, 2, 3, first=1, second=2)

Let’s see the output.

Adding (1, 2, 3)
Adding {'first': 1, 'second': 2}
Hello, world!

Next: Python Map, Filter, Reduce

by AICorr Team

We are proud to offer our extensive knowledge to you, for free. The AICorr Team puts a lot of effort in researching, testing, and writing the content within the platform (aicorr.com). We hope that you learn and progress forward.