gpt4 book ai didi

python - 遍历返回 NotImplemented 的 Python 特殊方法的 MRO

转载 作者:太空宇宙 更新时间:2023-11-03 14:23:20 25 4
gpt4 key购买 nike

我有一个代数对象的类层次结构,它实现了特殊方法,例如 __mul__ 和 __add__ ,并使用多重继承。我以某种方式假设 Python (>= 3.5) 会遍历方法解析顺序 (mro) 来查找第一个不返回 NotImplemented 的方法。唉,事实似乎并非如此。考虑以下最小示例:

class A():
def __mul__(self, other):
return "A * %s" % other

class B():
def __mul__(self, other):
if isinstance(other, int):
return "B * %s" % other
else:
return NotImplemented

class C(B, A):
pass

class D(B, A):
def __mul__(self, other):
res = B.__mul__(self, other)
if res is NotImplemented:
res = A.__mul__(self, other)
return res

在此代码中,我已实现具有所需行为的 D:

>>> d = D()
>>> d * 1
'B * 1'
>>> d * "x"
'A * x'

但是,我实际上希望 C 的行为与 D 相同,但事实并非如此:

>>> c = C()
>>> c * 1
'B * 1'
>>> c * "x"
Traceback (most recent call last):
File "<ipython-input-23-549ffa5b5ffb>", line 1, in <module>
c * "x"
TypeError: can't multiply sequence by non-int of type 'C'

当然,我明白发生了什么:我只是返回 mro 中第一个匹配方法的结果(我只是希望 NotImplemented 将作为特殊值处理)

我的问题是,是否有任何方法可以避免编写像 D.__mul__ 这样的样板代码(对于所有类的所有数字特殊方法来说,这基本上是相同的)。我想我可以编写一个类装饰器或元类来自动生成所有这些方法,但我希望有一些更简单的(标准库)方法,或者,有人已经做了类似的事情。

最佳答案

当你要求时,Python 会执行 MRO,这并不意味着要继续检查更高的值。更改您的代码以使用带有 super() 的协作继承(将 MRO 移动到下一个类的请求),否则您将返回 NotImplemented 并且它应该可以工作。它根本不需要 CD 来定义 __mul__,因为它们不会为其功能添加任何内容:

class A():
def __mul__(self, other):
return "A * %s" % other

class B():
def __mul__(self, other):
if isinstance(other, int):
return "B * %s" % other
try:
return super().__mul__(other) # Delegate to next class in MRO
except AttributeError:
return NotImplemented # If no other class to delegate to, NotImplemented

class C(B, A):
pass

class D(B, A):
pass # Look ma, no __mul__!

然后测试:

>>> d = D()
>>> d * 1
'B * 1'
>>> d * 'x'
'A * x'

super() 的神奇之处在于,它甚至可以在多重继承场景中工作,其中一个类(在本例中为 B)对 A 一无所知 code>,但如果一个 child 碰巧继承了它(或任何其他可用的类),仍然会很乐意委托(delegate)给它(或任何其他可用的类)。如果没有,我们会像以前一样处理生成的 AttributeError 以使结果 NotImplemented ,所以像这样的东西会按预期工作(它会尝试 str code> 的 __rmul__ 无法识别非 int 并会爆炸):

>>> class E(B): pass
>>> e = E()
>>> e * 1
'B * 1'
>>> e * 'x'
Traceback (most recent call last)
...
TypeError: can't multiply sequence by non-int of type 'E'

关于python - 遍历返回 NotImplemented 的 Python 特殊方法的 MRO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47804919/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com