如何在 NamedTuple 上重载 `+`

How do I overload `+` on a NamedTuple

如何在 3.5 中为命名元组创建 plus 的自定义重载?我知道 3.6 中有一些新的语法,你能在 3.5 中做到吗?我希望它也能通过 mypy 检查。

from typing import NamedTuple


Point = NamedTuple('Point',[('x',int),
                            ('y',int)])

def joinPoints(a: Point, b:Point) -> Point:
    return Point(x = a.x+b.x,y=a.y+b.y)

q = Point(1,2)
r = Point(3,4)
s= joinPoints(q,r)
t = q+r #HOW DO I MAKE THIS GO?
#s should equal t

请注意,Python 3.6 中用于定义类型化命名元组的新的基于 class 的语法最终在运行时所做的基本上是一堆元编程 hijinkery 来制作自定义 class,它恰好也包含您的自定义 __add__ 方法,如果您包含一个的话。

由于我们无法在 Python 3.5 中使用该语法,恐怕您真正能做的最好的事情就是自己实现所有样板文件。

记住,namedtuples 基本上是定义简单 classes(子class 元组)的便捷方式,仅此而已。如果你想要更复杂的东西,你实际上需要自己实现它。


无论如何,完全抛开类型,没有一种超级干净的方法来做你在运行时想做的事情,更不用说类型了(在至少,据我所知)。我想一种干净的方法是在定义点 class 之后手动修补它,如下所示:

from typing import NamedTuple

Point = NamedTuple('Point', [('x', int), ('y', int)])

def add(self: Point, other: Point) -> Point:
    return Point(self.x + other.x, self.y + other.y)

Point.__add__ = add

a = Point(1, 2)
b = Point(3, 4)

print(a + b)  # prints 'Point(4, 6)'

但是,您将不得不放弃使用 mypy -- mypy 做出简化(并且通常是合理的)假设 class 的属性和类型签名在那之后不会改变 class 已定义,因此将不允许为 Point 分配新方法,因此将在最后一行抛出错误。

也许有一些更聪明的方法(也许以某种方式使用 abc 模块?)最终会让您、Python 运行时和 mypy 满意,但我目前还不知道这样的方法。