Python 一种用于类型检查的NamedTuple子类的方法
我有几个共享一些字段的namedtuple。我有一个接受这些元组的函数,并保证只与共享字段交互。我想在mypy中键入这样的代码 代码的一个例子是:Python 一种用于类型检查的NamedTuple子类的方法,python,typing,namedtuple,mypy,Python,Typing,Namedtuple,Mypy,我有几个共享一些字段的namedtuple。我有一个接受这些元组的函数,并保证只与共享字段交互。我想在mypy中键入这样的代码 代码的一个例子是: from typing import NamedTuple class Base(NamedTuple): x: int y: int class BaseExtended(NamedTuple): x: int y: int z: str def DoSomething(tuple: Base):
from typing import NamedTuple
class Base(NamedTuple):
x: int
y: int
class BaseExtended(NamedTuple):
x: int
y: int
z: str
def DoSomething(tuple: Base):
return tuple.x + tuple.y
base = Base(3, 4)
base_extended = BaseExtended(5, 6, 'foo')
DoSomething(base)
DoSomething(base_extended)
当我在此代码上运行mypy时,会出现一个可预测的错误:
mypy_example.py:20:error:DoSomething的参数1已被删除
不兼容类型“BaseExtended”;预期“基数”
是否没有办法构造我的代码并保持mypy类型检查?我无法从Base继承BaseExtended,因为NamedTuple继承实现中存在错误:
我也不想使用难看的“Union[Base,BaseExtended]”,因为当我尝试对列表进行打字检查时,这会中断,因为“List[Union[Base,BaseExtended]]”与“List[BaseExtended]”不相等,这是因为mypy在变量/协变类型方面的魔力:
我应该放弃这个想法吗?有人建议对类型系统进行扩展,允许结构子类型(静态鸭式类型)。另外,
typing.NamedTuple
的运行时实现也将很快得到改进,可能在6月底的Python 3.6.2中(这也将通过PyPI上的typing
进行后端口)。命名元组的构造方式使得继承typing.NamedTuple
类成为可能。您必须编写自己的元类来扩展typing.NamedTupleMeta
类,以使子类化工作正常,即使这样
相反,您希望使用新的定义类并实现继承:
from dataclasses import dataclass
@dataclass(frozen=True)
class Base:
x: int
y: int
@dataclass(frozen=True)
class BaseExtended(Base):
z: str
该模块在Python3.7中是新的,但是您可以在Python3.6上使用它
上面定义了两个具有x
和y
属性的不可变类,其中BaseExtended
类又添加了一个属性BaseExtended
是Base
的完整子类,因此出于键入目的,它符合DoSomething()
函数的要求
这些类不是完整命名的元组,因为它们没有长度或支持索引,但是通过创建继承自collections.abc.Sequence
的基类,添加两个方法来按索引访问字段,可以轻松地添加这些类。如果将order=True
添加到@dataclass()
装饰器中,则实例将变得完全可排序,与(命名)元组的方式相同:
from collections.abc import Sequence
from dataclasses import dataclass, fields
class DataclassSequence(Sequence):
# make a dataclass tuple-like by accessing fields by index
def __getitem__(self, i):
return getattr(self, fields(self)[i].name)
def __len__(self):
return len(fields(self))
@dataclass(frozen=True, order=True)
class Base(DataclassSequence):
x: int
y: int
MyPy;在版本0.600中,由于无法识别数据类
模块导入,或者生成了\uuuu新方法,因此仍然会出现错误
在Python3.6和更早版本中,您还可以安装以实现相同的效果;使用attrs
,上述序列基类如下所示:
from collections.abc import Sequence
import attr
class AttrsSequence(Sequence):
# make a dataclass tuple-like by accessing fields by index
def __getitem__(self, i):
return getattr(self, attr.fields(type(self))[i].name)
def __len__(self):
return len(attr.fields(type(self)))
@attr.s(frozen=True, auto_attribs=True)
class Base(AttrsSequence):
x: int
y: int
dataclasses
直接基于attrs
,而attrs
提供了更多的功能;mypy完全支持使用attrs
生成的类,谢谢。我猜在3.6.2之前,你不知道我可以使用什么优雅的变通方法?如果是这样的话,我就接受答案,继续前进。@wuzwm不,不幸的是我不知道。改进还没有实现,同样的问题仍然适用于Python 3.6.5和3.7.0b4。实际上,运行时更改是故意放弃的。决定命名元组应保持最低限度,对于所有复杂用例,用户应使用数据类。