【问题标题】:Proper typing for class function decorator类函数装饰器的正确类型
【发布时间】:2020-11-17 14:08:46
【问题描述】:

键入print_before 函数装饰器的正确方法是什么,以便 Wrapped 函数具有正确的类型,但我不能在不起作用的类上使用装饰器?

谢谢

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)

【问题讨论】:

    标签: python mypy pyright


    【解决方案1】:

    装饰器有一个非常通用的类型。您对包装器的唯一了解是它至少接受一个未知类型的参数,并返回一些未知类型。至于装饰器本身,你只知道它返回的东西与它的参数类型相同。

    实际上,我们还知道一件事。无论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

    【讨论】:

    • 但我也知道self不能是Any,因为它需要定义一个函数print_hi
    • 修复了这个问题,但仍然不太正确:我们还可以假设返回值涉及参数使用的同一类(尽管可能是子类)。
    • 认为它现在已经修复了,但我现在无法测试它。
    • 感谢您的帮助!最新的迭代现在不允许这两种用法:D 类型“(self:PrintThings,a:int,b:int)-> int”的参数不能分配给“(p0:T,p1:Tuple [ Any, ...]) -> Any" in function "print_before" ... "Tuple[Any, ...]" is incompatible with "int" 函数接受的位置参数太少;预计 3 个,但收到 2 个
    • 据我了解,我相信这是解决我的问题所必需的:python.org/dev/peps/pep-0612 并且它只会在一年内与 python 3.10 一起提供
    猜你喜欢
    • 2019-07-23
    • 1970-01-01
    • 2015-10-23
    • 2011-06-06
    • 2011-10-04
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 2021-12-04
    相关资源
    最近更新 更多