Python provides a simple, yet powerful syntax called ‘decorators’. A decorator is a function or class that wraps (decorates) a function or a method. The ‘decorated’ function or method will replace the original ‘undecorated’ function or method. Because functions are first-class objects in Python, this can be done ‘manually’, but using the @decorator syntax is clearer and thus preferred.

def foo():
    # do something

def decorator(func):
    # manipulate func
    return func

foo = decorator(foo) # Manually decorate

def bar():
    # Do something

# bar() is decorated

This mechanism is useful for separating concerns and avoiding external unrelated logic ‘polluting’ the core logic of the function or method.

A good example of a piece of functionality that is better handled with decoration is memoization or caching: you want to store the results of an expensive function in a table and use them directly instead of recomputing them when they have already been computed. This is clearly not part of the function logic.