Декораторы — это мощный инструмент в языке программирования Python, который позволяет модифицировать поведение функций и классов без изменения их исходного кода. В этом уроке мы подробно рассмотрим, что такое декораторы, как они работают и как их использовать в своих проектах.
Что такое декораторы Python?
Декораторы в Python представляют собой особый вид функций, которые принимают другую функцию в качестве аргумента и возвращают новую функцию, изменяя ее поведение. Они позволяют создавать дополнительную функциональность для существующего кода, не изменяя его напрямую.
Простой пример декоратора:
def simple_decorator(func):
def wrapper():
print("Перед вызовом функции")
func()
print("После вызова функции")
return wrapper
@simple_decorator
def say_hello():
print("Привет!")
say_hello()
В этом примере simple_decorator
— это декоратор, который оборачивает функцию say_hello
. Когда мы вызываем say_hello()
, на самом деле выполняется декорированная версия функции.
Как работают декораторы Python?
Когда мы используем синтаксис @decorator
перед определением функции, Python автоматически передает эту функцию декоратору. Декоратор принимает эту функцию в качестве аргумента, создает новый объект-функцию (обычно называемый «wrapper» или «обертка») и возвращает его. Этот новый объект заменяет оригинальную функцию.
Декораторы, принимающие аргументы
Декораторы могут также принимать параметры. Давайте рассмотрим пример:
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Привет, {name}!")
greet("Алиса")
В этом примере декоратор repeat
принимает аргумент times
, который определяет, сколько раз будет вызвана декорируемая функция.
Применение декораторов Python
Декораторы имеют множество применений в Python. Вот несколько примеров использования декораторов:
1. Логирование:
import logging
def log_function_call(func):
def wrapper(*args, **kwargs):
logging.info(f"Вызвана функция {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_function_call
def add(a, b):
return a + b
result = add(3, 5)
print(result)
2. Измерение времени выполнения:
import time
def measure_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Функция {func.__name__} выполнялась {end_time - start_time:.2f} секунд")
return result
return wrapper
@measure_time
def slow_function():
time.sleep(2)
slow_function()
3. Кэширование результатов:
def cache_result(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@cache_result
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(100))
Декораторы классов
Декораторы могут также применяться к классам, позволяя изменять поведение классов. Вот пример:
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Database:
def __init__(self):
print("Инициализация базы данных")
db1 = Database()
db2 = Database()
print(db1 is db2) # Выведет: True
Использование functools.wraps
При создании декораторов важно сохранять метаданные декорируемой функции (такие как имя и документация). Для этого в стандартную библиотеку Python включен декоратор functools.wraps
:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Это документация обертки"""
print("Перед выполнением")
result = func(*args, **kwargs)
print("После выполнения")
return result
return wrapper
@my_decorator
def say_hello(name):
"""Это документация оригинальной функции"""
print(f"Привет, {name}!")
say_hello("Мир")
print(say_hello.__name__) # Выведет: say_hello
print(say_hello.__doc__) # Выведет: Это документация оригинальной функции
Декораторы — это мощный инструмент в арсенале Python-разработчика. Они позволяют создавать чистый, модульный код, расширять поведение функций и классов без изменения их исходного кода. Библиотеки Python широко используют декораторы для реализации различных паттернов проектирования и добавления функциональности.
Практикуйтесь в создании и использовании декораторов, и вы сможете писать более элегантный и эффективный код на Python. Помните, что возможности применения декораторов ограничены только вашим воображением!