Python 中使用 Pylance 的类型安全抽象属性

问题描述 投票:0回答:2

我遵循了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"

是否可以在抽象父类中指定抽象属性,以便在继承类中可以用文字值覆盖它?

python python-typing pyright
2个回答
1
投票

因此,根据具体用途,有几种不同的选项。如果你想在抽象类中定义属性类型,可以像这样完成:

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"

请参阅此处了解更多详情。请注意,这些选项都没有强制要求必须像属性一样重写属性,但这只是它的工作方式。希望这有帮助!


0
投票

这段代码相对(?)很好:您声明了一个协议

Abstract
,它至少需要类型为
title
的只读
str
属性。您的
Concrete
满足该要求。而且,这实际上是一个众所周知的食谱

相应的

pyright
ticket更能说明这个问题。区别在于类访问:
Abstract
意味着从类访问将产生一个
property
对象,但
Concrete
提供了一个普通的
str
。这种差异在某些内省或元编程案例中可能很重要。

我不同意 Eric Traut 的观点(今天晚些时候将开一张票来扩展这一点 - 感谢您让我注意到这一点!),因为这种行为似乎与 PEP-544 准则相矛盾(使用

Protocol
基础)而不是示例中的
ABC
不会改变 Pyright 输出):

要定义只读协议变量,可以使用(抽象)属性。

mypy
按原样接受您的代码(请参阅上面的食谱和playground)。如果您的目标是满足
pyright
,您应该使用属性覆盖,或者添加忽略注释,或者寻找一些解决方法。我更喜欢
# type: ignore
评论,因为我确实认为这是一个类型检查器错误,但这取决于你。

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