Правильная типизация для декоратора функций класса

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

благодарю вас

def print_before(func):
    def func_wrapper(self, *args):
        self.print_hi()
        return func(self, *args)
    return func_wrapper


class PrintThings:
    def print_hi(self):
        print("hi")

    @print_before
    def add_nums(self, a: int, b: int) -> int:
        return a + b


pt = PrintThings()
pt.add_nums(5, 4)


class ShouldNotWork:
    @print_before
    def add_nums(self, a: int, b: int) -> int:
        return a + b


snw = ShouldNotWork()
snw.add_nums(4, 5)

2 ответа

Как написано, декоратор имеет очень общий тип. Единственное, что вы знаете об оболочке, это то, что она принимает хотя бы один аргумент неизвестного типа и возвращает какой-то неизвестный тип. Что касается самого декоратора, вы знаете только, что он возвращает что-то того же типа, что и его аргумент.

Собственно, мы знаем еще кое-что. Независимо от типа self есть, он должен иметь print_hiметод. Мы можем представить это, используя Protocol.

Мы также вводим переменную типа T, который представляет один и тот же класс (или его подкласс) каждый раз, когда он используется в подписи print_before.

from typing import Any, Tuple, Protocol, TypeVar

class PrintsHi(Protocol):
    def print_hi(self):
        pass


T = TypeVar('T', bound=PrintsHi)


def print_before(func: Callable[[T, Tuple[Any,...]], Any]) -> Callable[[T, Tuple[Any,...]], Any]:
    def func_wrapper(self: T, *args: Tuple[Any,...]):
        self.print_hi()
        return func(self, *args)
    return func_wrapper

Я бы посмотрел на typing.Callable для набора функций. Или для классов / объектов typing.Protocol.

Другие вопросы по тегам