如何注释可以实现为属性的属性?

问题描述 投票:1回答:1

[我正在努力让mypy对我的类型注释感到满意。这是最小的示例:

class FooInterface:
    x: int


class FooWithAttribute(FooInterface):
    x: int = 0


class FooWithProperty(FooInterface):
    @property
    def x(self) -> int:
        return 0

据我的理解,一切都很好:FooWithAttribute().xFooWithProperty().x都将返回0,即int,没有类型错误。但是mypy抱怨:

error: Signature of "x" incompatible with supertype "FooInterface"

是否可以告诉mypy一切正常?现在,我发现的唯一方法是在x: typing.Any中注释FooInterface,这浪费了x为int的信息。

python properties typing mypy
1个回答
0
投票

Mypy实际上指出了程序中的合法错误。为了演示,假设您有一个如下所示的程序:

def mutate(f: FooInterface) -> None:
    f.x = 100

似乎很好,对吧?但是,如果我们执行mutate(FooWithProperty()),会发生什么? Python实际上会以AttributeError崩溃!

Traceback (most recent call last):
  File "test.py", line 19, in <module>
    mutate(FooWithProperty())
  File "test.py", line 16, in mutate
    f.x = 100
AttributeError: can't set attribute

为了使Mypy开心,您基本上有两个选择:

  1. 使FooInterface.x也是只读属性
  2. FooWithProperty.x设置可写器使其可写

我猜在您的情况下,您可能希望采用方法1。如果这样做,mypy将正确指出不允许使用f.x = 100行:

from abc import abstractmethod

class FooInterface:
    # Marking this property as abstract is *optional*. If you do it,
    # mypy will complain if you forget to define x in a subclass.
    @property
    @abstractmethod
    def x(self) -> int: ...

class FooWithAttribute(FooInterface):
    # No complaints from mypy here: having this attribute be writable
    # won't violate the Liskov substitution principle -- it's safe to
    # use FooWithAttribute in any location that expects a FooInterface.
    x: int = 0

class FooWithProperty(FooInterface):
    @property
    def x(self) -> int:
        return 0

def mutate(f: FooInterface) -> None:
    # error: Property "x" defined in "FooInterface" is read-only
    f.x = 100

mutate(FooWithProperty())

不幸的是,由于bug in mypy,方法2尚未完全起作用-mypy无法正确理解如何处理带有属性的属性。在这种情况下,解决方法是使FooInterface.x具有setter的属性。

© www.soinside.com 2019 - 2024. All rights reserved.