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

JPF*_*oia 5 python annotations type-hinting mypy

我最近发现了mypy,并且希望对其进行类型检查。

我有一个Connector基类:

class Connector():
    ... some methods, but no __init__ ...
Run Code Online (Sandbox Code Playgroud)

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

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


class Tube(Connector)
    def __init__():
        short_name = "T"
Run Code Online (Sandbox Code Playgroud)

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

c1 = Siphon()
c2 = Tube()
list_connectors: List[Connector] = list()
list_connectors.append(c1)
list_connectors.append(c2)
Run Code Online (Sandbox Code Playgroud)

现在让我们说我想编写一个函数以列表形式返回所有连接器的所有短名称。我会这样写:

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
Run Code Online (Sandbox Code Playgroud)

当我这样做时,mypy抱怨:

error: "Connector" has no attribute "short_name"
Run Code Online (Sandbox Code Playgroud)

的确如此,基类连接器没有此属性,只有子类。但是所有连接器子类都将具有此属性。

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

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

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

Mar*_*ers 13

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

class Connector:
    short_name: str
Run Code Online (Sandbox Code Playgroud)

这使用 Python 3.6 的Variable Annotation语法,这是 Python 3.6 或更新版本中的新内容。它定义了一个实例属性的类型,而不是一个类属性(有一个单独的语法)。

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

class Connector:
   short_name = ''  # type: str
Run Code Online (Sandbox Code Playgroud)

  • @Rififi 阅读 PEP 链接。`var: Type` 是实例类型提示。`var: Typing.ClassVar[Type]` 是类类型提示。您的实例将仅共享类型提示,而不共享值。 (2认同)

FHT*_*ell 5

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

class Connector():
    short_name: str
    ...
Run Code Online (Sandbox Code Playgroud)

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


另一种选择是做

import abc
class Connector(abc.ABC):
    @property
    @abc.abstractmethod
    def short_name(self) -> str:
        ...
Run Code Online (Sandbox Code Playgroud)