Logo Craft Homelab Docs Контакты Telegram
Декораторы в Python: примеры, асинхронные функции, кеширование и контекстные менеджеры — подробное руководство
manual
Tue Nov 04 2025

Декораторы, асинхронные функции и контекстные менеджеры в Python

В этой статье разберём несколько ключевых возможностей Python: создание декораторов разных видов, работу с асинхронными функциями, кеширование результатов и написание собственных контекстных менеджеров.

Декораторы позволяют изменить или расширить поведение функции без изменения её исходного кода. По сути, это функция, принимающая другую функцию и возвращающая новую, «обёрнутую» версию.

Простой декоратор

Наиболее базовый пример — декоратор без параметров. Он принимает функцию и возвращает новую функцию, которая вызывает оригинальную.

@deco
def my_func():
	pass
	
my_func = deco(my_func)
from typing import Callable

def deco(func: Callable):
	def wrapper():
		res = func()
		return res
	return wrapper

В этом примере wrapper вызывает func и возвращает её результат. Запись с @deco полностью эквивалентна ручному присваиванию my_func = deco(my_func).

Функция с параметром

Если исходная функция принимает аргументы, то и обёртка должна уметь их обрабатывать. В этом случае используются *args и **kwargs, чтобы поддерживать произвольный набор параметров.

@deco
def my_func(arg_func):
	pass
	
my_func = deco(my_func)(arg_func)
from typing import Callable

def deco(func: Callable):
	def wrapper(arg_func): # *args, **kwargs
		res = func(arg_func) # *args, **kwargs
		return res
	return wrapper

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

Декоратор с параметрами

Иногда самого декоратора недостаточно, и требуется передавать аргументы в сам декоратор. Тогда структура становится вложенной: функция-декоратор возвращает функцию-обёртку, которая уже принимает декорируемую функцию.

Также важно сохранять метаданные функций (__name__, __doc__). Для этого используется functools.wraps.

@deco(arg_deco)
def my_func(arg_func):
	pass
	
my_func = deco(arg_deco)(my_func)(arg_func)
from typing import Callable
from functools import wraps

def deco(arg_deco):
	def wrapper(func: Callable):
		@wraps(func)
		def inner(arg_func): # *args, **kwargs
			res = func(arg_func) # *args, **kwargs
			return res
		return inner
	return wrapper

Такая структура подходит, например, когда декоратору нужны настройки, передаваемые пользователем.

Декораторы для асинхронных функций

Асинхронные функции (async def) требуют специальной обработки — их необходимо вызывать с помощью await. Поэтому для таких случаев создаются асинхронные обёртки.

@deco
async def my_func():
	return 1
	
my_func = deco(my_func)
from typing import Coroutine

def deco(coroutine: Coroutine):
	async def wrapper(*args, **kwargs):
		ret = await coroutine(*args, **kwargs)
		return ret
	return wrapper

Декоратор превращается в асинхронный (async def wrapper), что позволяет корректно «ожидать» выполнение исходной корутины.

Кэширование результата функции

Python предоставляет удобный механизм кэширования — functools.lru_cache. Он позволяет сохранять результаты вызовов функций и повторно использовать их без повторных вычислений.

from functools import lru_cache # least-recently-used

@lru_cache
def my_long_calc():
	time.sleep(5)
	return 42

# все 3 функции выполнятся одновременно
print(my_long_calc())
print(my_long_calc())
print(my_long_calc())

В данном примере фактически длительная функция вызывается только один раз — последующие вызовы используют кэш.

Создание своего контекстного менеджера

Контекстные менеджеры используются для автоматического выполнения действий при входе и выходе из блока with. Они могут управлять ресурсами, логировать события и выполнять завершающие операции.

Python предоставляет удобный декоратор @contextmanager, позволяющий писать контекстные менеджеры без создания отдельного класса.

from contextlib import contextmanager

@contextmanager
def ctx_manager():
	print('hello')
	yield
	print('end')

with ctx_manager() as man:
	print('print')

Функция, помеченная @contextmanager, разделяется оператором yield на две части:

  • код до yield выполняется при входе в блок with,
  • код после yield выполняется при выходе.

Заключение

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

Эти механизмы часто используются в веб-разработке, асинхронном программировании, логировании, тестировании и многих других сферах, поэтому их понимание существенно упрощает написание чистого и эффективного кода.