Что такое декоратор? Как написать собственный декоратор?
В Python декоратор — это функция, которая принимает другую функцию и возвращает новую функцию с изменённым или дополненным поведением, не изменяя исходный код.
Это мощный инструмент, который позволяет писать чистый, переиспользуемый и лаконичный код.
🔷 Что такое декоратор простыми словами?
Декоратор — это как обёртка для функции. Он «улучшает» или добавляет функциональность, не трогая саму функцию.
📦 Представь: у тебя есть подарок (функция), и ты завернул его в красивую обёртку (декоратор) — внутри всё тот же подарок, но снаружи он выглядит лучше или делает что-то ещё.
✅ Синтаксис декоратора:
@decorator_name
def my_function():
...
Это сокращение от:
def my_function():
...
my_function = decorator_name(my_function)
🔧 Как работает декоратор?
Декоратор — это функция, которая принимает функцию как аргумент и возвращает другую функцию (обычно вложенную).
🔍 Пример:
def my_decorator(func):
def wrapper():
print("Перед вызовом функции")
func()
print("После вызова функции")
return wrapper
@my_decorator
def say_hello():
print("Привет!")
say_hello()
📤 Вывод:
Перед вызовом функции
Привет!
После вызова функции
🔨 Как написать собственный декоратор?
Шаг 1: Напиши функцию-декоратор, принимающую другую функцию.Шаг 2: Определи вложенную wrapper-функцию.Шаг 3: Верни эту wrapper.
💡 Пример с аргументами:
def decorator(func):
def wrapper(\*args, \*\*kwargs): # передаёт любые аргументы
print("Вызов функции с аргументами:", args, kwargs)
result = func(\*args, \*\*kwargs)
print("Результат:", result)
return result
return wrapper
@decorator
def add(a, b):
return a + b
add(2, 3)
📤 Вывод:
Вызов функции с аргументами: (2, 3) {}
Результат: 5
📌 Зачем нужны декораторы?
-
Логирование (запись в журнал)
-
**Авторизация/проверка доступа
** - **Измерение времени работы функции
** - **Кэширование
** - **Повторное выполнение при ошибке
** - **Валидация данных
**
🧪 Примеры полезных декораторов
1. Логирование:
def log(func):
def wrapper(\*args, \*\*kwargs):
print(f"Вызов {func.\__name_\_} с {args}, {kwargs}")
return func(\*args, \*\*kwargs)
return wrapper
@log
def greet(name):
return f"Привет, {name}!"
greet("Миша")
2. Измерение времени:
import time
def timer(func):
def wrapper(\*args, \*\*kwargs):
start = time.time()
res = func(\*args, \*\*kwargs)
end = time.time()
print(f"Функция {func.\__name_\_} работала {end - start:.4f} секунд")
return res
return wrapper
@timer
def long_task():
time.sleep(1)
long_task()
3. Повторная авторизация (пример с проверкой):
def authorized(func):
def wrapper(\*args, \*\*kwargs):
if kwargs.get("user") != "admin":
print("Доступ запрещён")
return None
return func(\*args, \*\*kwargs)
return wrapper
@authorized
def delete_data(user=None):
print("Данные удалены")
delete_data(user="guest") # Доступ запрещён
delete_data(user="admin") # Данные удалены
🎯 Особенности:
- **Декораторы можно накладывать друг на друга:
**
@dec1
@dec2
def func():
...
\# сначала dec2, потом dec1
- **Функция functools.wraps сохраняет имя и документацию:
**
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(\*args, \*\*kwargs):
return func(\*args, \*\*kwargs)
return wrapper
- Можно писать декораторы с параметрами — это вложенные функции:
def repeat(times):
def decorator(func):
def wrapper(\*args, \*\*kwargs):
for _ in range(times):
func(\*args, \*\*kwargs)
return wrapper
return decorator
@repeat(3)
def hello():
print("Привет")
hello()