By using the properties of nested functions, you can surround a function with another function in so-called wrapping. I’ll walk through some examples where this can be helpful.

Example 1

We create a function that sleeps for one second, and we wish to time it.

import time

def my_func(n):
    time.sleep(1)
# This is the simplest way

start = time.time()
my_func(1)
end = time.time()
print('Took:', end - start)
Took: 1.0006980895996094
def decorator_func(func):

    def wrapper(s):
        start = time.time()
        func(s)
        end = time.time()
        print('Took:', end - start)

    return wrapper

dec = decorator_func(my_func)
dec(1)
Took: 1.0018470287322998

Syntax

Python allows you to call the decorator using the @ symbol, which works inside a class object.

@decorator_func
def my_func(n):
    time.sleep(1)
my_func(3)
Took: 1.0009677410125732

Example 2

We create another function with the same name that adds one to the input value.

def decorator_func(func):

    def wrapper(s):
        print('Before')
        func(s)
        print('After')

    return wrapper

dec = decorator_func(my_func)
@decorator_func
def my_func(n):
    print(n+1)
my_func(2)
Before
3
After
@decorator_func
@decorator_func
def my_func(n):
    print(n+1)
my_func(3)
Before
Before
4
After
After

More useful decorators at Python Decorator Library