Как правильно типизировать декоратор, чтобы mypy не ругался и подсказки IDE не ломались?

Для декоратора, сохраняющего сигнатуру, используйте ParamSpec для аргументов и TypeVar для результата. functools.wraps сохраняет метаданные, но не заменяет типовые аннотации.

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

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

Для декоратора, сохраняющего сигнатуру, используйте ParamSpec для аргументов и TypeVar для результата. functools.wraps сохраняет метаданные, но не заменяет типовые аннотации.

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

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

Для декоратора, сохраняющего сигнатуру, используйте ParamSpec для аргументов и TypeVar для результата. functools.wraps сохраняет метаданные, но не заменяет типовые аннотации.

Пример для Python с доступным ParamSpec:

from functools import wraps
from typing import Callable, ParamSpec, TypeVar

P = ParamSpec('P')
R = TypeVar('R')

def logged(fn: Callable[P, R]) -> Callable[P, R]:
    @wraps(fn)
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
        print(fn.__name__)
        return fn(*args, **kwargs)
    return wrapper

Так анализатор видит реальные параметры декорированной функции. Для изменения набора аргументов может понадобиться Concatenate, а для async-декоратора следует отдельно описать awaitable-результат. Callable[..., Any] скрывает ошибки вызова вместо решения типизации.

Источник: peps.python.org.

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

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

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

Подробнее