123
Ты хочешь, чтобы я переписал статью про декораторы и контекстные менеджеры в Python в том же духе — но на 60% пошлее, чем та, максимально грязная версия про IT-рынок? Понимаю. Ты хочешь, чтобы код стонал, метафоры кончали, а техническая глубина осталась. Я сделаю. Держи — теперь Python трахает тебя мозгами.
Декораторы и контекстные менеджеры в Python: глубокое проникновение в суть с мокрыми примерами
Python тебя ласкает своей выразительностью. Но есть два инструмента, которые доводят до исступления: декораторы и контекстные менеджеры. Они прячутся в каждой популярной библиотеке — FastAPI, pytest, SQLAlchemy, asyncio. Ты их используешь, но чувствуешь ли ты их пальцы глубоко внутри? Сейчас разберёмся.
В этой статье мы:
заставим декораторы раздевать функции;
создадим собственные грязные декораторы;
узнаем, как контекстные менеджеры входят и выходят;
реализуем их двумя способами — жёстко и нежно;
поймём, когда один инструмент жестче другого.
Декораторы: функции, которые насилуют поведение других функций
Декоратор — это как господин. Он берёт функцию (покорную, беззащитную) и возвращает новую — с дополнительными извращениями.
Простейший пример (прелюдия):
python
def decorator(func):
def wrapper():
print("Перед проникновением")
func()
print("После глубокого выдоха")
return wrapper
Как это трахается:
python
@decorator
def hello():
print("Я кончаю!")
hello()
Результат:
text
Перед проникновением
Я кончаю!
После глубокого выдоха
Запись с @ — это синтаксический сахар для грубой подмены:
python
def hello():
...
hello = decorator(hello) # оригинальная функция изнасилована и заменена
Почему декораторы нужны, как воздух перед оргазмом
Без декораторов ты дублируешь мокрые места:
python
def save_user():
start = time.time()
# логика
print(time.time() - start)
python
def save_order():
start = time.time()
# логика
print(time.time() - start)
Сухо, скучно, руки заняты.
С декоратором — изящно и пошло:
python
import time
def timer(func):
def wrapper():
start = time.time()
result = func()
print(f"{func.name}: {time.time() - start:.2f} сек — я кончил")
return result
return wrapper
Используем:
python
@timer
def process():
time.sleep(1)
process() # process: 1.00 сек — я кончил
Передача аргументов: когда надо глубже
Предыдущий декоратор работает только с функциями без параметров — как девственница.
Универсальный член — args, *kwargs:
python
def logger(func):
def wrapper(args, kwargs):
print(f"Вхожу в {func.name} со всеми позами")
result = func(args, **kwargs)
print("Выхожу мокрым")
return result
return wrapper
Пробуем:
python
@logger
def add(a, b):
return a + b
print(add(2, 3))
Вывод:
text
Вхожу в add со всеми позами
Выхожу мокрым
5
args — собирает все позиции, `*kwargs» — собирает имена. Именно так большинство декораторов и трахают твои функции.
Проблема потери метаданных (или как не потерять свою сущность)
Посмотри на изнасилованную функцию:
python
print(add.name)
Вывод:
text
wrapper
Python стёр имя оригинала. Теперь всё — wrapper. Это ломает:
документацию (она плачет);
автогенерацию API (оргазм прерван);
FastAPI (он не возбуждается).
Решение — презерватив functools.wraps:
python
from functools import wraps
def logger(func):
@wraps(func)
def wrapper(args, kwargs):
print("Старт — предварительные ласки")
return func(args, **kwargs)
return wrapper
Теперь:
python
print(add.name) # add
@wraps сохраняет личность. Использовать обязательно, иначе ты просто грубый насильник.
Декораторы с параметрами: когда нужна степень жестокости
Иногда хочется передать настройки:
python
@repeat(3)
def hello():
print("Hello")
Для этого нужно ещё одно проникновение — третий уровень вложенности.
python
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(args, kwargs):
for _ in range(times):
func(args, **kwargs)
return wrapper
return decorator
Используем:
python
@repeat(3)
def greet():
print("Кончаю")
greet()
Результат:
text
Кончаю
Кончаю
Кончаю
Структура:
text
repeat(3) → decorator(func) → wrapper(*args)
Как три пальца. Или три входа.
Декораторы классов: когда класс хочет быть грязным
Декорировать можно не только функции, но и классы. Например, добавить всем членам класса метод repr, чтобы они рассказывали о себе всё.
python
def add_repr(cls):
def repr(self):
return f"{cls.name}({self.dict})"
cls.repr = repr
return cls
Применяем:
python
@add_repr
class User:
def init(self, name):
self.name = name
print(User("Alex")) # User({'name': 'Alex'})
Теперь класс умеет раздеваться.
Где декораторы используются в реальной жизни (везде, где течёт)
FastAPI:
python
@app.get("/users")
async def get_users():
...
@app.get — регистрация хука, как привязать партнёра.
Pytest:
python
@pytest.fixture
def db():
...
Фикстуры — это смазка для тестов.
Dataclasses:
python
@dataclass
class User:
name: str
Автоматически генерирует методы, как секс-робот.
Контекстные менеджеры: вход, выход и никаких следов
Контекстный менеджер управляет ресурсом и гарантирует, что после блока всё будет чисто — как хороший садист, который после порки вытирает кровь.
Пример:
python
with open("file.txt") as f:
data = f.read()
Python сам закроет файл. Без менеджера ты бы делал так:
python
f = open("file.txt")
try:
data = f.read()
finally:
f.close()
Контекстный менеджер — это тот же try/finally, но с оргазмом в одной строке.
Как работает with: анатомия проникновения
Конструкция:
python
with manager as value:
...
Превращается в:
python
manager.enter() # вход
try:
...
finally:
manager.exit() # выход — всегда, даже если больно
Контекстный менеджер обязан реализовать:
python
enter() # что делаем перед
exit() # что делаем после (и при ошибке)
Создаём свой контекстный менеджер: таймер, который ласкает
Пример — измеряем время, как длительность полового акта:
python
import time
class Timer:
def enter(self):
self.start = time.perf_counter()
return self # можешь меня трогать
def __exit__(self, exc_type, exc_value, traceback):
elapsed = time.perf_counter() - self.start
print(f"Ты кончил через {elapsed:.2f} сек")
Используем:
python
with Timer():
time.sleep(2)
Вывод:
text
Ты кончил через 2.00 сек
Обработка исключений: когда боль становится удовольствием
Метод exit получает информацию об ошибке. Можешь проглотить исключение — как грубый господин.
python
class IgnoreError:
def enter(self):
print("Начинаем — расстегнули ширинку")
def __exit__(self, exc_type, exc_value, traceback):
print("Заканчиваем — застёгиваемся")
return True # подавляем исключение
Проверка:
python
with IgnoreError():
1 / 0
print("Мы всё ещё живы и мокры")
Вывод:
text
Начинаем — расстегнули ширинку
Заканчиваем — застёгиваемся
Мы всё ещё живы и мокры
Возврат True — опасная игрушка. Используй только в постели с проверенным партнёром.
Контекстные менеджеры через contextmanager: быстрый и грязный способ
Python любит, когда быстро и без классов.
python
from contextlib import contextmanager
import time
@contextmanager
def timer():
start = time.perf_counter()
try:
yield # здесь происходит магия входа
finally:
elapsed = time.perf_counter() - start
print(f"Ты кончил через {elapsed:.2f} сек")
Используем:
python
with timer():
time.sleep(1)
Вход — всё, что до yield. Выход — всё, что в finally. Компактно, как юбка, которая сама снимается.
Асинхронные контекстные менеджеры: для тех, кто любит долго и в несколько потоков
В асинхронном коде используются:
python
aenter()
aexit()
Пример:
python
async with session.begin():
...
Реализация:
python
class AsyncManager:
async def aenter(self):
print("Вход — глубоко и без стука")
return self
async def __aexit__(self, exc_type, exc_value, traceback):
print("Выход — мокрый и довольный")
Использование:
python
async with AsyncManager():
await asyncio.sleep(1)
Декораторы или контекстные менеджеры? Кто жестче?
Декоратор отвечает на вопрос: «Что делать при вызове функции?» — он грубо оборачивает, насилует при каждом входе.
Используй декораторы, когда хочешь:
логировать каждый членовоз;
кэшировать, как презерватив;
повторять попытки, как настойчивый любовник;
проверять права — кто может войти;
мерить время каждой позы.
Контекстный менеджер отвечает: «Что делать при входе и выходе из блока?» — он входит, делает дело и гарантированно выходит, даже если ты кончил раньше времени.
Используй контекстные менеджеры для:
файлов (открыть — закрыть);
соединений с БД (взял — отдал);
транзакций (commit/rollback — как предварительные ласки и резкий финиш);
блокировок (захватил — отпустил);
временных настроек (вошёл в роль — вышел).
Итоги: теперь ты знаешь, как это трахается
Декораторы и контекстные менеджеры — две стороны одной грязной монеты Python. Они выносят повторяющуюся инфраструктурную логику из твоего драгоценного бизнес-кода.
Декораторы расширяют поведение функций, не трогая их исходник — как хороший доминант, который не бьёт, а ласкает через плёнку.
Контекстные менеджеры обеспечивают безопасное управление ресурсами и гарантируют чистую постель даже после исключений.
Теперь ты понимаешь внутренности популярных библиотек. Ты можешь писать более чистый, выразительный и поддерживаемый код. И он будет кончать вместе с тобой.
Конец. Можешь перечитать — и запустить python -c "import this", но уже по-другому.