Декораторы в Python: что это такое, как работают и зачем нужны

онлайн тренажер по питону
Онлайн-тренажер Python 3 для начинающих

Теория без воды. Задачи с автоматической проверкой. Подсказки на русском языке. Работает в любом современном браузере.

начать бесплатно

🔍 Введение

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

Декораторы в Python позволяют "оборачивать" одну функцию в другую, изменяя или расширяя её поведение без изменения исходного кода. Они используются повсеместно: в Flask, Django, FastAPI, pytest, и даже в стандартной библиотеке.

В этой статье мы глубоко разберем:

  • Что такое декораторы в Python;

  • Как они устроены;

  • Как писать свои;

  • Где и зачем их использовать.


💡 Что такое декоратор в Python?

Декоратор — это функция, которая принимает другую функцию и возвращает новую функцию (или модифицированную старую).

Простой пример:

python
def decorator(func): def wrapper(): print("До вызова") func() print("После вызова") return wrapper @decorator def say_hello(): print("Привет!") say_hello()

📌 Вывод:

 
До вызова Привет! После вызова

@decorator — это просто синтаксический сахар для:

python
say_hello = decorator(say_hello)

⚙️ Как это работает внутри

Чтобы понять декораторы, нужно знать:

  • В Python функции — объекты.

  • Можно передавать функции как аргументы.

  • Можно определять функции внутри других.

Это и называется замыканием (closure).

Минимальный шаблон декоратора:

python
def decorator(func): def wrapper(*args, **kwargs): # Можно что-то сделать до result = func(*args, **kwargs) # И после return result return wrapper

📦 Примеры декораторов

Декоратор времени выполнения:

python
import time def timing(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f"{func.__name__} заняло {time.time() - start:.4f} сек") return result return wrapper @timing def slow_func(): time.sleep(1) slow_func()

Декоратор авторизации:

python
def require_admin(func): def wrapper(user, *args, **kwargs): if user != "admin": raise PermissionError("Доступ запрещён") return func(user, *args, **kwargs) return wrapper @require_admin def delete_database(user): print("База удалена!") delete_database("admin") # работает

Декоратор с аргументами (фабрика декораторов)

python
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): func(*args, **kwargs) return wrapper return decorator @repeat(3) def greet(): print("Привет!") greet()

🧪 Встроенные декораторы в Python

Декоратор Назначение
@staticmethod Создаёт статический метод класса
@classmethod Метод, принимающий класс как cls
@property Превращает метод в атрибут
@functools.lru_cache Кэширует результат функции

🔄 functools.wraps

Чтобы не терялись __name__, __doc__, __module__, нужно использовать functools.wraps:

python
from functools import wraps def decorator(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper

Без этого say_hello.__name__ будет wrapper, а не say_hello.


📚 Примеры из практики

Django

python
from django.contrib.auth.decorators import login_required @login_required def dashboard(request): ...

Flask

python
@app.route('/home') def home(): return "Hello Flask"

pytest

python
@pytest.mark.parametrize("a,b,result", [(1,2,3), (2,3,5)]) def test_sum(a, b, result): assert a + b == result

🛠️ Использование нескольких декораторов

python
@decorator_a @decorator_b def func(): pass

Эквивалент:

python
func = decorator_a(decorator_b(func))

🧠 Best practices

  • Используйте @wraps всегда.

  • Не создавайте вложенные декораторы без надобности.

  • Не злоупотребляйте декораторами с побочными эффектами.

  • Помните: декораторы применяются при импорте, не при вызове.


⚠️ Частые ошибки

Ошибка Как избежать
Неиспользование @wraps Добавить @wraps над wrapper()
Потеря аргументов Использовать *args, **kwargs
Декоратор с аргументами не работает Обернуть в фабрику: @repeat(3)

🧾 Заключение

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

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


❓FAQ

В: Что такое декоратор в Python?
О: Это функция, которая оборачивает другую функцию, расширяя или изменяя её поведение.

В: Как работает @?
О: Это синтаксический сахар для func = decorator(func).

В: Можно ли передавать аргументы декоратору?
О: Да, через фабрику: @decorator(arg).

В: Что делает @wraps?
О: Сохраняет имя и документацию оригинальной функции.

В: Декораторы — это функциональное программирование?
О: Да, это часть функционального стиля в Python.

Новости