Декоратор может при создании обёртки проверить inspect.iscoroutinefunction и вернуть async wrapper для coroutine-функции, обычный wrapper — для синхронной. Метаданные сохраняют через functools.wraps.
Как сделать один декоратор, работающий и с синхронными, и с асинхронными функциями?
Декоратор может при создании обёртки проверить inspect.iscoroutinefunction и вернуть async wrapper для coroutine-функции, обычный wrapper — для синхронной. Метаданные сохраняют через functools.wraps.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Декоратор может при создании обёртки проверить inspect.iscoroutinefunction и вернуть async wrapper для coroutine-функции, обычный wrapper — для синхронной. Метаданные сохраняют через functools.wraps.
Пример:
from functools import wraps
from inspect import iscoroutinefunction
def decorate(fn):
if iscoroutinefunction(fn):
@wraps(fn)
async def async_wrapper(*args, **kwargs):
return await fn(*args, **kwargs)
return async_wrapper
@wraps(fn)
def sync_wrapper(*args, **kwargs):
return fn(*args, **kwargs)
return sync_wrapper
Общую логику добавляют в обе ветки. Это решение для обычных функций: синхронная функция, возвращающая awaitable, и async generator требуют отдельного контракта, а не угадывания по имени.