如何使用支持简单类型和 属性 的字段声明协议?

How to declare a Protocol with a field which supports both a simple type and property?

(相关但不重复:

我想创建一个Protocol,其中一个字段既可以用简单类型实现,也可以用属性实现。例如:

class P(Protocol):
    v: int


@dataclass
class Foo(P):
    v: int


class Bar(P):
    @property
    def v(self) -> int: # ERROR
        return

但是上面的代码没有类型检查。我该如何解决?

注意:我想解决这个问题而不重写FooBar,因为FooBar不是我实现的

根据 this issue,以下代码不是解决方案,因为只读 property 和简单成员的语义略有不同。

class P(Protocol):
    @property
    def v(self) -> int: # declare as property
        ...

Pyright 否认 Protocol 由于差异。

一般来说,使用只读 property 声明 Protocol,而不是 read/write 字段:

class P(Protocol):
    @property
    def v(self) -> int:
        pass

这是必需的,因为 read-only propertyread[=29= 都满足只读协议属性]/写字段。相比之下,read/write 协议属性仅由 read/write 字段满足,而不是 read-only property.


由于 PyRight 坚持认为字段和属性是不同种类的属性,因此必须使用两种变体声明属性——一次作为字段,一次作为属性。对于简单的协议,这可以通过声明一个单独的字段和 属性 的 属性 变体来完成:

# field only
class Pf(Protocol):
    v: int

# property only
class Pp(Protocol):
    @property
    def v(self) -> int:
        return 1

# Either field or property
P = Union[Pf, Pp]

这对 MyPy 和 PyRight 都有效。