我有一个类,它是成员的容器。所有成员都是同一类型。
class A(int):
def __init__(self, n):
super().__init__()
self.n = n
def do(self):
print('adding 10')
return self.n + 10
class B:
def __init__(self, a1, a2):
self.a = [a1, a2]
def __getattr__(self, item):
return getattr(self.a[0], item)
a1 = A(10)
a2 = A(5)
b = B(a1, a2)
__getattr__
覆盖 do
方法:
In[7]: b.do()
adding 10
Out[7]: 20
甚至在显式调用时覆盖
__add__
In[8]: b.__add__(1)
Out[8]: 11
但是
__add__
当被称为 +
时会失败
In[9]: b+1
TypeError: unsupported operand type(s) for +: 'B' and 'int'
如何重写魔术方法以按预期工作?
__getattr__
不处理运算符的原因在为什么 __getattr__ 能够处理 python 2.x 中的内置运算符重载?
在新式类中,特殊方法总是在类中查找(隐式查找)而不是实例中。
我的解决方法(并不完美,但允许使其工作)是在
B
中显式定义所需的 dunder 方法,并在它们上显式调用 __getattr__
:
class B:
def __init__(self, a1, a2):
self.a = [a1, a2]
def __add__(self,other):
return self.__getattr__("__add__")(other)
def __getattr__(self, item):
return getattr(self.a[0], item)
想添加对Maximouse的评论的答案,以说明元类不能解决这个问题。给定:
class Meta(type):
def __getattr__(self, name):
return "meta-attr"
class X(metaclass=Meta):
def __getattr__(self, name):
return "attr"
然后:
>>> X().__add__(X())
"attr"
>>> X.__add__(X(), X())
"meta-attr"
但这失败了:
>>> X() + X()
TypeError: unsupported operand type(s) for +: 'Derived' and 'Derived'
...
这意味着这没有实现 OP 的目标。使用 dis,我们可以看到在底层 python 甚至从不进行属性查找,它只是调用
BINARY_ADD
:
>>> from dis import dis
>>> a, b = X(), X()
>>> dis("a + b")
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 BINARY_ADD
6 RETURN_VALUE
(在 python 3.8 上测试)