Декораторы в Python: полное руководство для начинающих
Автор: Javohir Abdullayev · · Python

Что такое декораторы в Python и зачем они нужны?
Когда вы начинаете писать код на Python, вы часто встречаете такие конструкции, как @property, @login_required (Django) или @dp.message() (Aiogram). Конструкции, начинающиеся с этого символа, называются декораторами (decorators). Многим начинающим разработчикам эта тема может показаться сложной и загадочной. На самом же деле декоратор — это очень удобный инструмент, позволяющий расширить возможности существующей функции (добавить дополнительное поведение), не изменяя её исходный код.
В этом руководстве мы шаг за шагом разберём механизм работы декораторов, начав с самых простых понятий и закрепив всё практическими примерами.
1. Функция — объект первого класса (First-Class Citizen)
Чтобы в полной мере понять декораторы, сначала необходимо разобраться, как работают функции в Python. В Python все функции являются объектами. Это означает, что вы можете:
- Присваивать функцию переменной;
- Передавать функцию в качестве аргумента другой функции;
- Возвращать функцию из другой функции в качестве результата.
Давайте рассмотрим простой пример:
def salom_ber(ism):
return f"Assalomu alaykum, {ism}!"
# Присваиваем функцию переменной
xabar = salom_ber
print(xabar("Ali")) # Результат: Assalomu alaykum, Ali!2. Вложенные функции и возврат функций
Внутри функции можно объявить другую функцию и вернуть её наружу. Это является фундаментом для понимания декораторов:
def tashqi_funksiya():
def ichki_funksiya():
return "Ichki funksiyadan salom!"
return ichki_funksiya
yangi_funksiya = tashqi_funksiya()
print(yangi_funksiya()) # Результат: Ichki funksiyadan salom!3. Создаём наш первый простой декоратор
Декоратор — это функция, которая принимает другую функцию в качестве аргумента, добавляет поверх неё дополнительную логику и возвращает обновлённую функцию.
def mening_dekoratorim(asosiy_funksiya):
def wrapper():
print("Funksiya ishga tushishidan oldin bajariladigan kod.")
asosiy_funksiya()
print("Funksiya ishlab bo'lgach bajariladigan kod.")
return wrapper
def oddiy_salom():
print("Salom, dunyo!")
# Способ декорирования:
bezatilgan_salom = mening_dekoratorim(oddiy_salom)
bezatilgan_salom()Синтаксический сахар: символ @
Чтобы не писать вручную bezatilgan_salom = mening_dekoratorim(oddiy_salom), в Python предусмотрен специальный символ @:
@mening_dekoratorim
def oddiy_salom():
print("Salom, dunyo!")
oddiy_salom()Оба способа дают абсолютно одинаковый результат, но синтаксис с @ выглядит гораздо более читаемым и лаконичным.
4. Декорирование функций, принимающих аргументы
В реальных проектах функции принимают различные аргументы. Чтобы функция-обёртка (wrapper) могла принимать любое количество параметров, используются *args и **kwargs:
def xabar_dekoratori(func):
def wrapper(*args, **kwargs):
print(f"[LOG] {func.__name__} funksiyasi ishga tushirildi.")
natija = func(*args, **kwargs)
print(f"[LOG] Funksiya o'z ishini yakunladi.")
return natija
return wrapper
@xabar_dekoratori
def hisobla(a, b):
return a + b
javob = hisobla(10, 25)
print(f"Natija: {javob}")5. Практический пример: измерение времени выполнения
В разработке часто требуется замерять время работы функций. Вместо дублирования кода в каждой отдельной функции мы можем решить эту задачу с помощью единого универсального декоратора:
import time
def vaqtni_olchash(func):
def wrapper(*args, **kwargs):
boshlanish = time.time()
natija = func(*args, **kwargs)
tugash = time.time()
sarflangan_vaqt = tugash - boshlanish
print(f"{func.__name__} funksiyasi {sarflangan_vaqt:.4f} soniyada bajarildi.")
return natija
return wrapper
@vaqtni_olchash
def katta_ro‘yxat_yaratish():
return [x ** 2 for x in range(1_000_000)]
katta_ro‘yxat_yaratish()6. Зачем нужен functools.wraps?
Когда мы оборачиваем функцию декоратором, метаданные исходной функции (её имя, docstring) перезаписываются данными функции-обёртки wrapper. Чтобы предотвратить это, на помощь приходит functools.wraps из стандартной библиотеки Python:
from functools import wraps
def xavfsiz_dekorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Bu wrapper funksiya."""
return func(*args, **kwargs)
return wrapper
@xavfsiz_dekorator
def foydalanuvchi_info():
"""Bu funksiya foydalanuvchi haqida ma'lumot beradi."""
pass
print(foydalanuvchi_info.__name__) # foydalanuvchi_info
print(foydalanuvchi_info.__doc__) # Bu funksiya foydalanuvchi haqida ma'lumot beradi.Всегда берите за правило использовать @wraps(func) при написании собственных декораторов. Это поможет избежать путаницы при отладке и написании автоматических тестов.
Заключение
Декораторы в Python — это мощный инструмент для поддержания чистоты кода (принцип DRY), логирования, контроля доступа и аутентификации в единой точке. Освоив базовые принципы из этого руководства, вам станет значительно проще и понятнее работать с такими популярными библиотеками и фреймворками, как Django, Flask, FastAPI или Aiogram.
Теги: #Python #Dekoratorlar #Backend #Dasturlash Asoslari