Walk MRO for Python special methods returning NotImplemented
我有一个代数对象类的层次结构,这些代数对象实现特殊的方法,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
在这段代码中,我使用所需的行为实现了
1 2 3 4 5 | >>> d = D() >>> d * 1 'B * 1' >>> d *"x" 'A * x' |
然而,我实际上希望
1 2 3 4 5 6 7 8 | >>> 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中第一个匹配方法的结果(我只是希望
我的问题是,是否有任何方法可以避免编写像
当您请求时,python会向mro走去,这并不是隐式地保持更高的检查级别。更改代码以使用与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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__! |
然后测试:
1 2 3 4 5 | >>> d = D() >>> d * 1 'B * 1' >>> d * 'x' 'A * x' |
1 2 3 4 5 6 7 8 | >>> 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' |