Как сделать декоратор, который работает и с синхронными, и с асинхронными функциями?

На этапе декорирования проверьте inspect.iscoroutinefunction и создайте async-обёртку для async def, обычную — для def. Обе должны сохранять аргументы, результат и исключения.

Короткий ответ

Что ответить на собеседовании

На этапе декорирования проверьте inspect.iscoroutinefunction и создайте async-обёртку для async def, обычную — для def. Обе должны сохранять аргументы, результат и исключения.

Подробный разбор

Ответ с пояснениями

На этапе декорирования проверьте inspect.iscoroutinefunction и создайте async-обёртку для async def, обычную — для def. Обе должны сохранять аргументы, результат и исключения.

import inspect
from functools import wraps

def traced(func):
    if inspect.iscoroutinefunction(func):
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            return await func(*args, **kwargs)
        return async_wrapper

    @wraps(func)
    def sync_wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return sync_wrapper

В соответствующую обёртку добавляют логирование или замер времени. Проверка покрывает обычные функции def и async def, но не все произвольные callable-объекты и синхронные фабрики awaitable. Для них нужно явно определить контракт. Нельзя вызывать asyncio.run внутри уже работающего event loop ради унификации.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее