Как создавать и использовать декораторы в Python

Узнайте, как писать и применять декораторы в Python. Освойте функции переноса, изменение поведения, обработку аргументов и сохранение метаданных с помощью переносов.

Попробуйте это решение в редакторе

Обзор

Декораторы — одна из самых элегантных и мощных синтаксических функций Python, позволяющая изменять поведение функции или класса без постоянного изменения их кода. Они широко используются для решения сквозных задач, таких как регистрация времени выполнения, обеспечение аутентификации пользователей, кэширование результатов (мемоизация) и аудит конечных точек API.

По сути, декоратор — это функция высшего порядка, которая принимает другую функцию в качестве аргумента, определяет вложенную функцию-оболочку, которая внедряет некоторую пользовательскую логику, и возвращает эту функцию-оболочку. Python предоставляет понятный сокращенный синтаксис с использованием символа `@` для применения декораторов к функциям, что делает их визуально элегантными.

При написании декораторов обычно требуется, чтобы декорированная функция поддерживала любое количество позиционных и ключевых аргументов. Этого можно добиться, разработав вложенную функцию-оболочку, принимающую `*args` и `**kwargs` и передающую их целевой функции. Кроме того, вам следует использовать functools.wraps в функции-оболочке, чтобы сохранить строку документации и метаданные имени исходной функции.

Код и вывод выполнения

Этот скрипт демонстрирует написание декоратора журналирования и обертку функции для проверки входных, выходных данных и метаданных.

from functools import wraps

# 1. Defining a decorator
def log_execution(func):
    @wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"[Log] Calling function: {func.__name__} with args: {args}")
        result = func(*args, **kwargs)
        print(f"[Log] Finished {func.__name__}. Result: {result}")
        return result
    return wrapper

# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
    """Adds two numbers and returns the sum."""
    return a + b

# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)

# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)
Терминальный выход
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.

Пошаговая реализация

  • Определите функцию внешнего декоратора, которая принимает целевую функцию в качестве аргумента.
  • Импортируйте и примените @functools.wraps(func) к вложенной функции-оболочке, чтобы защитить исходные метаданные.
  • Реализуйте оболочку(*args, **kwargs) для захвата входных переменных, внедрения логики и вызова целевой функции.
  • Верните объект функции-обертки из блока заголовка декоратора.
  • Примените декоратор, используя @decorator_name непосредственно над сигнатурой целевой функции.

Часто задаваемые вопросы

Почему @functools.wraps необходим внутри декораторов?

Без оберток декорированная функция теряет свою первоначальную идентичность (ее атрибуты __name__ и __doc__ заменяются атрибутами вложенной функции-обертки), что затрудняет отладку и самоанализ кода.

Могу ли я применить несколько декораторов к одной функции?

Да! Вы можете объединить декораторы, поместив в стек несколько строк @. Python применяет их снизу вверх (первой выполняется ближайшая к определению функции).

Связанные темы

Рекомендуемые ресурсы Python

Расширьте свои знания с помощью соответствующих интерактивных руководств, шпаргалок и сравнений кода.