EMZETT.
Login

Python: decorators

In short: A decorator is a function that takes another function and returns an extended version. You apply it with @name above the function.

In more detail: It wraps the original function to do something before or after: time it, check access, cache results, log calls.

In Depth

import functools, time
 
def timing(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = f(*args, **kwargs)
        print(f.__name__, time.perf_counter() - start)
        return result
    return wrapper
 
@timing
def compute(n): ...
  • Equivalent: @timing above compute is the same as compute = timing(compute).
  • functools.wraps: Preserves name and documentation of the original function. Without it the function looks like wrapper.
  • With parameters: A decorator with arguments (@repeat(3)) is a function returning a decorator (one more level of nesting).
  • Built in and well known: @staticmethod, @property, @functools.lru_cache, routes in Flask (@app.route), @pytest.fixture.
  • Classes: Decorators can also extend classes (@dataclass).
  • Note: Do not confuse with the design pattern, see decorator pattern.

See also: dataclasses, lambda