🐛 Типичные ошибки

⚡ Топ-3 ошибки

  • Забыть вернуть результат из wrapper — вернётся None.
  • Не использовать @functools.wraps — имя и документация функции теряются.
  • Путать порядок стекирования декораторов.

Ошибка 1. Потеря результата

Проблема: результат оригинальной функции не возвращается.

def upper_decorator(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs).upper()  # результат не возвращается
    return wrapper


@upper_decorator
def get_text():
    return "hello"


print(get_text())  # None

Исправление:

def upper_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs).upper()
    return wrapper

Ошибка 2. Потеря метаданных

Проблема: без functools.wraps декорированная функция называется wrapper.

def simple_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper


@simple_decorator
def example_function():
    """Original function."""
    pass


print(example_function.__name__)  # wrapper
print(example_function.__doc__)   # None

Исправление:

import functools


def simple_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Ошибка 3. Неправильный порядок декораторов

Проблема: ожидается один результат, а получается другой из-за порядка.

@border
@repeat
def f(): ...  # repeat применяется первым

@repeat
@border
def g(): ...  # border применяется первым

Исправление: помните, что декораторы выполняются снизу вверх, то есть ближайший к функции — первым.

Ошибка 4. Аргументы не передаются

Проблема: обёртка не принимает аргументы, поэтому декорированная функция не может быть вызвана с параметрами.

def bad_decorator(func):
    def wrapper():
        return func()
    return wrapper


@bad_decorator
def add(a, b):
    return a + b


add(2, 3)  # TypeError

Исправление: используйте def wrapper(*args, **kwargs).

Ошибка 5. Декоратор с аргументами без фабрики

Проблема: пытаются использовать два уровня вместо трёх.

@framed("-")  # TypeError: framed missing func
def show(): ...

Исправление: для параметризованных декораторов нужна фабрика:

def framed(symbol: str):
    def decorator(func):
        def wrapper(*args, **kwargs):
            ...
        return wrapper
    return decorator