Декораторы аннотаций mypy в Python __call__

Я пытаюсь аннотировать декоратор, реализованный как класс, но mypy, похоже, либо теряет аннотацию, либо теряет тип и думает, что это Any. Что я пытаюсь аннотировать:

class my_decorator:
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

@my_decorator
def func():
    return 2

Как мне аннотировать это, чтобы функция определялась как возвращающая int после украшения? Я понимаю, что приведенное выше выглядит просто, и я мог бы преобразовать my_decorator в функцию, но на самом деле он разделен на подклассы, чтобы иметь более специализированные параметры.


person user2084911    schedule 22.10.2020    source источник


Ответы (1)


Вам нужно будет сделать my_decorator универсальным классом и сделать что-то вроде следующего:

from typing import Any, Callable, Generic, TypeVar

T = TypeVar('T')

class my_decorator(Generic[T]):
    def __init__(self, func: Callable[..., T]) -> None:
        self.func = func

    def __call__(self, *args: Any, **kwargs: Any) -> T:
        return self.func(*args, **kwargs)

@my_decorator
def func() -> int:
    return 2

То есть зафиксируйте возвращаемый тип вашей функции с помощью TypeVar, который привязан к вашему классу my_decorator. Это гарантирует, что значение, привязанное к TypeVar, будет доступно, когда мы попытаемся использовать его при анализе любых вызовов __call__.

К сожалению, невозможно гарантировать, что параметры __call__ будут соответствовать параметрам func(). Итак, mypy не будет сообщать об ошибке, если вы попытаетесь сделать что-то вроде func(1, 2, 3).

Это может стать возможным после того, как mypy добавит поддержку PEP 612, улучшающего поддержка набора кода, связанного с декораторами в целом.

person Michael0x2a    schedule 25.10.2020