根据mypy文档,如果某个类需要引用自身,则可以使用forward-reference。
这似乎适用于普通类,但是我无法使用继承自NamedTuple的类。
"""
All this code runs without error on Python 3.6
The question is why the 'B' class' __add__ method
raises an error through mypy.
"""
from typing import *
class A:
def __init__(self, x: int) -> None:
self.x = x
def __add__(self, other: 'A') -> 'A':
return type(self)(self.x + other.x)
def __str__(self) -> str:
return f'A(x={self.x})'
A1 = A(1)
A2 = A(2)
A3 = A1 + A2
print(A3)
class B(NamedTuple('B', [('x', int)])):
# The following line will raise an error in mypy
# error: Argument 1 of "__add__" incompatible with supertype "tuple"
def __add__(self, other: 'B') -> 'B':
return type(self)(self.x + other.x)
B1 = B(1)
B2 = B(2)
B3 = B1 + B2
print(B3)
更新:Guido van Rossum自己回答this question on Github。
我不是100%肯定你要完成的任务,但是根据你的初始例子,我猜你想重新定义+ B类,以便在B的实例上实现元素添加。原因mypy默认不支持这种情况称为“Liskov替换原则”(你可以谷歌解释)。
然而,有一种解决办法:将#type:忽略在产生错误的行上(def 添加行)。这不是合理的,但只要您从未将B实例传递给假定它是元组的代码并尝试在其上进行元组连接,它就会执行您想要的操作。
答案 0 :(得分:1)
B.__add__
的类型声明表明,将B
的实例添加到另一个B
实例是有效的(并且实现支持这个,因为它期望{{1} }} 上班)。但是,该方法会覆盖来自other.x
(通过__add__
)的更通用的tuple
方法,该方法可以将任意两个元组连接在一起(因此右侧可以是一个实例namedtuple
或任何tuple
- 子类)。因为您的新方法对其参数有更严格的类型要求,所以您的类(从tuple
的角度来看)不是mypy
的正确子类。你不能将你的类的实例放到以前使用过元组的地方,并让它的工作方式相同。
考虑这个功能:
tuple
这适用于普通元组,但如果您将def tuple_append(tup: tuple, value: any) -> tuple:
return tup1 + (value,)
个实例之一传递为B
,它将失败(即使您传入的是tup
子类的实例因为函数的类型声明需要)。这就是tuple
不认为您的mypy
类型有效的原因。如果它接受B
,其他具有正确类型声明的代码可能会意外中断。
不幸的是,我认为围绕这个问题没有好办法。 Python没有其他语言所做的“私有继承”的概念。在没有公开成为子类的情况下,没有办法从另一个类继承实现。