Python Glossary Русский

all Python 3Functionsterm

Decorators

decorators

A higher-order function that wraps another function to change its behavior. Applied with the @ syntax.

Syntax

@decorator
def func(): ...

Writing @deco above def f is exactly f = deco(f), evaluated once when the function is defined. The classic pitfall: without functools.wraps the wrapper stands in for the original, so f.__name__, its docstring and signature are lost — help() and tracebacks start lying; wrap your wrapper in @wraps(func).

Examples

def my_dec(func):
    def wrapper(*args, **kwargs):
        print('before')
        result = func(*args, **kwargs)
        print('after')
        return result
    return wrapper
@my_dec
def say(): print('hi')
say()  # → before / hi / after
import time
def timer(func):
    def wrapper(*args, **kwargs):
        t = time.perf_counter()
        res = func(*args, **kwargs)
        print(f'{func.__name__}: {time.perf_counter() - t:.2f}s')
        return res
    return wrapper
@timer
def slow(): time.sleep(0.01)
slow()  # → ? около slow: 0.01s — зависит от машины
from functools import wraps
def logged(func):
    @wraps(func)
    def wrapper(*a, **kw):
        print(f'Calling {func.__name__}')
        return func(*a, **kw)
    return wrapper
@logged
def add(a, b): return a + b
print(add(1, 2))  # → Calling add / 3
# Декоратор с аргументами
def repeat(n):
    def decorator(func):
        def wrapper(*a, **kw):
            for _ in range(n):
                func(*a, **kw)
        return wrapper
    return decorator
@repeat(3)
def hi(): print('hi')
hi()  # → hi / hi / hi
# Стек декораторов: применяются снизу вверх
@my_dec
@logged
def greet(name): return f'Hi {name}'
greet('Alice')  # → before / Calling greet / after
# Декоратор для проверки типа
def check_int(func):
    def wrapper(n):
        if not isinstance(n, int):
            raise TypeError('int expected')
        return func(n)
    return wrapper
@check_int
def triple(n): return n * 3
print(triple(4))  # → 12
# Сохранение имени функции (@wraps)
from functools import wraps
def noop(f):
    @wraps(f)
    def w(*a,**kw): return f(*a,**kw)
    return w
@noop
def my_func(): pass
print(my_func.__name__)  # → my_func

See also

Open in the full glossarydocs.python.orgReport an inaccuracy