你问什么可以做到,而且很容易。例如:
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)
所以超级用magic方法工作的原因并不是因为它不可能。原因必须在别处。原因之一是这样做会违反等于(==
)的合同。除此之外,这是等同的,是对称的。这意味着如果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
的另一个原因是,一旦超做搜索它给对象的MRO,它就必须给自己一个机会,以提供所要求的属性 - 超级对象仍然在自己的权利的对象 - 我们应该能够测试与其他对象的平等,要求字符串表示,并反思超级正在使用的对象和类。如果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__
属性(该属性确实存在)。我们得到该方法并调用它,从而再次启动整个过程。如果我们没有在超级方面编写__iadd__
方法并使用super().__iadd__(other)
,那么这绝不会发生。相反,我们会收到关于没有属性__iadd__
的超级对象的错误消息。有点神秘,但不如无限堆栈轨迹。
所以super不能用magic方法工作的原因是它创造了比解决问题更多的问题。
http://stackoverflow.com/questions/12047847/super-object-not-calling-getattr – 2014-09-19 01:15:09
也有帮助:https://docs.python.org/3/reference/datamodel.html#special-method-查找 – wim 2015-06-10 03:51:20