您的要求可以轻松完成。例如:
class dundersuper(super):
def __add__(self, other):
# this works, because the __getattribute__ method of super is over-ridden to search
# through the given object's mro instead of super's.
return self.__add__(other)
super = dundersuper
class MyInt(int):
def __add__(self, other):
return MyInt(super() + other)
i = MyInt(0)
assert type(i + 1) is MyInt
assert i + 1 == MyInt(1)
所以 super 使用魔法方法的原因并不是因为它不可能。原因一定在别处。一个原因是这样做会违反平等合同(==)。也就是说,除其他标准外,平等是对称的。这意味着如果a == b 为真,那么b == a 也必须为真。这让我们陷入了一个棘手的境地,super(self, CurrentClass) == self,但self != super(self, CurrentClass) 例如。
class dundersuper(super):
def __eq__(self, other):
return self.__eq__(other)
super = dundersuper
class A:
def self_is_other(self, other):
return super() == other # a.k.a. object.__eq__(self, other) or self is other
def __eq__(self, other):
"""equal if both of type A"""
return A is type(self) and A is type(other)
class B:
def self_is_other(self, other):
return other == super() # a.k.a object.__eq__(other, super()), ie. False
def __eq__(self, other):
return B is type(self) and B is type(other)
assert A() == A()
a = A()
assert a.self_is_other(a)
assert B() == B()
b = B()
assert b.self_is_other(b) # assertion fails
另一个原因是,一旦 super 完成搜索,它会获得对象的 mro,然后它必须给自己一个机会来提供请求的属性 - super 对象本身仍然是一个对象 - 我们应该能够测试与其他对象相等,请求字符串表示,并内省 super 正在使用的对象和类。如果 dunder 方法在超级对象上可用,但在可变对象所代表的对象上不可用,这会产生问题。例如:
class dundersuper(super):
def __add__(self, other):
return self.__add__(other)
def __iadd__(self, other):
return self.__iadd__(other)
super = dundersuper
class MyDoubleList(list):
"""Working, but clunky example."""
def __add__(self, other):
return MyDoubleList(super() + 2 * other)
def __iadd__(self, other):
s = super()
s += 2 * other # can't assign to the result of a function, so we must assign
# the super object to a local variable first
return s
class MyDoubleTuple(tuple):
"""Broken example -- iadd creates infinite recursion"""
def __add__(self, other):
return MyDoubleTuple(super() + 2 * other)
def __iadd__(self, other):
s = super()
s += 2 * other
return s
对于列表示例,函数__iadd__ 可以更简单地写成
def __iadd__(self, other):
return super().__iadd__(other)
对于元组示例,我们陷入了无限递归,这是因为tuple.__iadd__ 不存在。因此,当在超级对象上查找属性__iadd__ 时,会检查实际超级对象的__iadd__ 属性(确实存在)。我们得到那个方法并调用它,这又开始了整个过程。如果我们没有在 super 上编写 __iadd__ 方法并使用 super().__iadd__(other),那么这将永远不会发生。相反,我们会收到关于没有属性__iadd__ 的超级对象的错误消息。有点神秘,但比无限堆栈跟踪要少。
所以 super 不能使用魔法方法的原因是它产生的问题比它解决的要多。