mypy:基类没有属性x,如何在基类中键入提示

Posted

技术标签:

【中文标题】mypy:基类没有属性x,如何在基类中键入提示【英文标题】:mypy: base class has no attribute x, how to type hint in base class 【发布时间】:2018-12-13 22:06:59 【问题描述】:

我最近发现了 mypy,我希望用它来检查我的代码。

我有一个Connector 基类:

class Connector():
    ... some methods, but no __init__ ...

我有几个子类,它们都是连接器,但类型不同:

class Siphon(Connector)
    def __init__():
        short_name = "S"


class Tube(Connector)
    def __init__():
        short_name = "T"

当我使用这些对象时,我通常将它们放在一个列表中:

c1 = Siphon()
c2 = Tube()
list_connectors: List[Connector] = list()
list_connectors.append(c1)
list_connectors.append(c2)

现在假设我想编写一个函数来返回所有连接器的所有短名称,作为一个列表。我会写这样的:

def get_names(list_connectors: List[Connector]) -> List[str]:
    tmp_list: List[str] = list()
    for c in list_connectors:
        tmp_list.append(c.short_name)
    return tmp_list

当我这样做时,mypy 会抱怨:

error: "Connector" has no attribute "short_name"

这是真的,基类连接器没有这个属性,只有子类。但是所有的 Connector 子类都会有这个属性。

我应该如何纠正?我不能在这里使用类属性,因为我的所有子类都需要它们自己的 short_name 属性。

我是否应该在 get_names 函数的类型提示中使用 Union(在我的现实生活中,连接器的类型远不止 2 种,我的 API 的用户可以添加自己的)?

我也不确定是否可以编写一个基本的 __init_ 函数并在子类中覆盖它,因为子类都有不同的 init

【问题讨论】:

【参考方案1】:

你会将该属性添加到基本类型中;你不需要给它一个值:

class Connector:
    short_name: str

这使用 Python 3.6 的 Variable Annotation syntax,这是 Python 3.6 或更高版本中的新功能。它定义了 instance 属性的类型,而不是类属性(有a separate syntax)。

你可以使用注释,此时你必须给属性一个初始值,并且是一个类属性:

class Connector:
   short_name = ''  # type: str

【讨论】:

但这不是类变量吗?我所有的Connector 对象都会共享它吗? @Rififi 阅读链接的 PEP。 var: Type 是实例类型提示。 var: typing.ClassVar[Type] 是类类型提示。您的实例将仅共享类型提示,而不是值。 @Rififi:我已经明确说明注释记录了实例属性的类型。【参考方案2】:

如果您使用的是 python 3.6 或更高版本,那么

class Connector():
    short_name: str
    ...

应该可以。这实际上并不存在于命名空间中,但 MYPY 会找到它。见https://www.python.org/dev/peps/pep-0526/。


另一种选择是做

import abc
class Connector(abc.ABC):
    @property
    @abc.abstractmethod
    def short_name(self) -> str:
        ...

【讨论】:

以上是关于mypy:基类没有属性x,如何在基类中键入提示的主要内容,如果未能解决你的问题,请参考以下文章

C#中基类属性值在子类中设置,如何在基类的方法中获取子类设置的值?

如何在构造函数中注入 IEnumerable<ICustomRepository>,以便我可以决定在基类中使用哪一个?

基类 派生类 类的继承与约束

在基类初始化(直接或间接)中使用覆盖属性的示例是啥?

在基类方法中引用继承类?

不能在基类中声明 Signal