我遵循了Python 3.3的答案:
class Abstract(ABC):
@property
@abstractmethod
def title(self) -> str: ...
class Concrete(Abstract):
title = "Test" # pylance error
但是在
Concrete
我收到 pylance 错误:
Expression of type "Literal['Test']" cannot be assigned to declared type "property"
"Literal['Test']" is incompatible with "property"
是否可以在抽象父类中指定抽象属性,以便在继承类中可以用文字值覆盖它?
因此,根据具体用途,有几种不同的选项。如果你想在抽象类中定义属性类型,可以像这样完成:
class Abstract(ABC):
title: str
class Concrete(Abstract):
title = "test"
这假设 title 的值可能会通过
Concrete
发生变化,而“test”只是默认值。
然而,您可能想要的是一个类变量。这只会由具体类设置它的值,而不会通过方法更新:
from typing import ClassVar
class Abstract(ABC):
title: ClassVar[str]
class Concrete(Abstract):
title = "test"
请参阅此处了解更多详情。请注意,这些选项都没有强制要求必须像属性一样重写属性,但这只是它的工作方式。希望这有帮助!
这段代码相对(?)很好:您声明了一个协议
Abstract
,它至少需要类型为title
的只读str
属性。您的 Concrete
满足该要求。而且,这实际上是一个众所周知的食谱。
相应的
pyright
ticket更能说明这个问题。区别在于类访问:Abstract
意味着从类访问将产生一个 property
对象,但 Concrete
提供了一个普通的 str
。这种差异在某些内省或元编程案例中可能很重要。
我不同意 Eric Traut 的观点(今天晚些时候将开一张票来扩展这一点 - 感谢您让我注意到这一点!),因为这种行为似乎与 PEP-544 准则相矛盾(使用
Protocol
基础)而不是示例中的 ABC
不会改变 Pyright 输出):
要定义只读协议变量,可以使用(抽象)属性。
mypy
按原样接受您的代码(请参阅上面的食谱和playground)。如果您的目标是满足 pyright
,您应该使用属性覆盖,或者添加忽略注释,或者寻找一些解决方法。我更喜欢 # type: ignore
评论,因为我确实认为这是一个类型检查器错误,但这取决于你。