我最近发现了 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
您可以将该属性添加到基本类型中;你不需要给它一个值:
class Connector:
short_name: str
这使用了 Python 3.6 的 Variable Annotation 语法,这是 Python 3.6 或更高版本中的新增功能。它定义了实例属性的类型,而不是类属性(有单独的语法)。
您可以使用注释,否则,此时您必须为属性指定一个初始值,并且是一个类属性:
class Connector:
short_name = '' # type: str
如果您使用的是 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:
...