Руководство по декораторам Python для продвинутых программистов
Декораторы Python — это мощный и гибкий инструмент для изменения поведения функций или методов. Они позволяют программистам расширять или изменять функциональность вызываемых объектов понятным, читаемым и поддерживаемым способом. В этой статье рассматриваются расширенные концепции, связанные с декораторами Python, включая вложенные декораторы, аргументы декораторов и декораторы на основе классов.
Кто такие декораторы?
Декораторы — это функции, которые изменяют поведение другой функции. Они оборачивают другую функцию, чтобы расширить ее поведение без явного изменения ее кода. Декораторы определяются с помощью синтаксиса @decorator_name
и размещаются над определением функции.
Базовый синтаксис декоратора
Простой декоратор принимает функцию в качестве аргумента, определяет внутреннюю функцию, которая добавляет некоторое поведение, а затем возвращает внутреннюю функцию.
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Функции декоратора с аргументами
Декораторы могут быть более гибкими, принимая аргументы. Чтобы создать такой декоратор, вам нужно написать функцию, которая возвращает декоратор. Это позволяет добавить более динамичное поведение декораторам.
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Декораторы для вложений
Декораторы могут быть вложенными для объединения нескольких поведений. Например, мы можем использовать два или более декораторов для одной функции.
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def repeat_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + result
return wrapper
@repeat_decorator
@uppercase_decorator
def say_word(word):
return word
print(say_word("hello"))
Декораторы на основе классов
В Python декораторы также могут быть реализованы как классы с помощью метода __call__
. Декораторы на основе классов полезны, когда вам нужно более сложное управление состоянием и поведением.
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"Call {self.num_calls} of {self.func.__name__!r}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
Использование functools.wraps
для сохранения метаданных
Когда вы пишете декораторы, декорированная функция теряет свои исходные метаданные, такие как имя и docstring. Декоратор functools.wraps
можно использовать для копирования метаданных исходной функции в функцию-обертку.
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Wrapper function executed before", func.__name__)
return func(*args, **kwargs)
return wrapper
@my_decorator
def display_info(name, age):
"""Displays name and age."""
print(f"display_info ran with arguments ({name}, {age})")
print(display_info.__name__) # Output: display_info
print(display_info.__doc__) # Output: Displays name and age.
Заключение
Декораторы Python — это мощная функция, которая позволяет гибко проектировать код и изменять поведение. Расширенное использование, например, вложенные декораторы, декораторы с аргументами и декораторы на основе классов, может обеспечить еще большую функциональность и читабельность программ Python. Понимая и правильно используя декораторы, разработчики могут писать более лаконичный, эффективный и читабельный код.