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

Yoh*_*hei 21 python typing mypy pyright

(相关但不重复:如何注释可以作为属性实现的属性?

我想创建一个Protocol,其中的字段可以通过简单类型和属性来实现。例如:

class P(Protocol):
    v: int


@dataclass
class Foo(P):
    v: int


class Bar(P):
    @property
    def v(self) -> int: # ERROR
        return
Run Code Online (Sandbox Code Playgroud)

但上面的代码没有进行类型检查。我应该如何修复它?

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

根据这个问题,下面的代码不是解决方案,因为只读成员property和简单成员具有细微不同的语义。

class P(Protocol):
    @property
    def v(self) -> int: # declare as property
        ...
Run Code Online (Sandbox Code Playgroud)

Protocol由于差异,皮赖特否认了这一点。

Mis*_*agi 17

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

\n
class P(Protocol):\n    @property\n    def v(self) -> int:\n        pass\n
Run Code Online (Sandbox Code Playgroud)\n

这是必需的,因为只读字段property/写字段都满足只读协议属性。相反,读/写协议属性仅由读/字段满足,而不是只读 property

\n
\n

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

\n
# field only\nclass Pf(Protocol):\n    v: int\n\n# property only\nclass Pp(Protocol):\n    @property\n    def v(self) -> int:\n        return 1\n\n# Either field or property\nP = Union[Pf, Pp]\n
Run Code Online (Sandbox Code Playgroud)\n

这对于 MyPy 和 PyRight 都有效。

\n