如何键入提示函数,在Python中通过类装饰器添加到类中

soat7uwm  于 2023-01-14  发布在  Python
关注(0)|答案(1)|浏览(130)

我有一个类装饰器,它向装饰的类添加一些函数和字段。

@mydecorator
@dataclass
class A:
    a: str = ""

(通过setattr())添加了一个.save()函数和一组作为单独指令的数据类字段信息。
我希望VScode和mypy能够正确识别它,以便在使用以下命令时:

a=A()
a.save()

a.my_fields_dict,正确地识别这2个。
有什么方法可以做到这一点吗?也许可以在运行时修改类A的类型注解?

vaqhlq81

vaqhlq811#

靶区; DR

您尝试做的事情在当前类型系统中是不可能的。

1.交叉点类型

如果通过装饰器添加到类中的属性和方法是静态的(从某种意义上说,它们不仅仅是在运行时已知的),那么通过混合protocolP,你所描述的实际上是对任何给定类T的扩展,该协议定义了方法save等等。
要对此进行注解,需要T & P的一个交集,如下所示:

from typing import Protocol, TypeVar

T = TypeVar("T")

class P(Protocol):
    @staticmethod
    def bar() -> str: ...

def dec(cls: type[T]) -> type[Intersection[T, P]]:
    setattr(cls, "bar", lambda: "x")
    return cls  # type: ignore[return-value]

@dec
class A:
    @staticmethod
    def foo() -> int:
        return 1

你可能会注意到Intersection的导入明显缺失了,这是因为尽管它是Python类型系统的most requested features之一,但到目前为止仍然缺失,目前还没有办法在Python类型中表达这个概念。

2.类装饰器问题

现在唯一的解决方法是定制一个实现,以及一个相应的插件,用于您选择的类型检查器。我刚刚偶然发现了typing-protocol-intersection包,它正好为mypy做了这件事。
如果您安装了它并将plugins = typing_protocol_intersection.mypy_plugin添加到您的mypy配置中,您可以编写如下代码:

from typing import Protocol, TypeVar

from typing_protocol_intersection import ProtocolIntersection

T = TypeVar("T")

class P(Protocol):
    @staticmethod
    def bar() -> str: ...

def dec(cls: type[T]) -> type[ProtocolIntersection[T, P]]:
    setattr(cls, "bar", lambda: "x")
    return cls  # type: ignore[return-value]

@dec
class A:
    @staticmethod
    def foo() -> int:
        return 1

但是这里我们遇到了下一个问题,通过mypy使用reveal_type(A.bar())测试这个问题将得到以下结果:

error: "Type[A]" has no attribute "bar"  [attr-defined]
note: Revealed type is "Any"

然而,如果我们这样做:

class A:
    @staticmethod
    def foo() -> int:
        return 1

B = dec(A)

reveal_type(B.bar())

我们没有收到mypynote: Revealed type is "builtins.str"的投诉。尽管我们之前所做的是等效的!
这不是插件的bug,而是mypy内部的bug。这是另一个long-standing issuemypy没有正确处理类装饰器。
该问题线程中的一个人甚至提到了您的用例以及所需的交集类型。

自己动手

换句话说,你只能等到这两个漏洞被修补好,或者你可以希望至少mypy的装饰器问题很快被修复,同时为交集类型编写你自己的VSCode插件,也许你可以和我上面提到的mypy插件背后的人聚在一起。

相关问题