首页 > 解决方案 > 如何使用同时支持简单类型和属性的字段声明协议?

问题描述

(相关,但不重复:How to annotate that can be implemented as property?

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

class P(Protocol):
    v: int


@dataclass
class Foo(P):
    v: int


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

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

注意:我想在不重写Fooand的情况下解决这个问题Bar,因为FooandBar不是我实现的。

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

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

Protocol由于差异,Pyright 否认了这一点。

标签: pythonmypytypingpyright

解决方案


通常,声明Protocol使用只读property字段,而不是读/写字段:

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

这是必需的,因为只读和/写字段都满足只读协议属性相反,读/写协议属性仅由读/字段满足,而不是只读字段property 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 都有效。


推荐阅读