在 Python website 上找到关于 super()
的文档说它返回一个代理对象,该对象将方法调用委托(delegate)给父类或兄弟类。在 super considered super 找到的信息, how does super() work with multiple inheritance 和 super considered harmful说明实际上使用了 mro
中的下一个方法。我的问题是,如果使用 super(object, self).some_method()
会发生什么?由于 object
通常出现在 mro
列表的末尾,我猜搜索将立即结束,但出现异常。但实际上,似乎调用了代理本身的方法,如 super(object, self).__repr__()
所示,显示了 super 对象本身。我想知道 super()
与 object
的行为是否根本不委托(delegate)方法。
如果是这种情况,我想知道是否有任何可靠的 Material 提到过它,以及它是否适用于其他 Python 实现。
class X(object):
def __init__(self):
# This shows [X, object].
print X.mro()
# This shows a bunch of attributes that a super object can have.
print dir(super(object, self))
# This shows something similar to <super object at xxx>
print(object, self)
# This failed with `super() takes at least one argument`
try:
super(object, self).__init__()
except:
pass
# This shows something like <super <class 'object'>, <'X' object>>.
print(super(object, self).__repr__())
# This shows the repr() of object, like <'X' object at xxx>
print(super(X, self).__repr__())
if __name__ == '__main__':
X()
最佳答案
如果 super
在查看要委托(delegate)给的方法解析顺序 (MRO) 时没有找到任何东西(或者如果您正在寻找属性 __class__
)它将检查它自己的属性。
因为 object
始终是 MRO 中的最后一个类型(至少据我所知,它始终是最后一个),您有效地禁用了委派并且它将仅检查 super 实例。
我发现这个问题真的很有趣,所以我查看了 super
的源代码,特别是委托(delegate)部分(super.__getattribute__
(in CPython 3.6.5)),我将它(粗略地)翻译成纯 Python 并附带一些额外的我自己的评论:
class MySuper(object):
def __init__(self, klass, instance):
self.__thisclass__ = klass
self.__self__ = instance
self.__self_class__ = type(instance)
def __repr__(self):
# That's not in the original implementation, it's here for fun
return 'hoho'
def __getattribute__(self, name):
su_type = object.__getattribute__(self, '__thisclass__')
su_obj = object.__getattribute__(self, '__self__')
su_obj_type = object.__getattribute__(self, '__self_class__')
starttype = su_obj_type
# If asked for the __class__ don't go looking for it in the MRO!
if name == '__class__':
return object.__getattribute__(self, '__class__')
mro = starttype.mro()
n = len(mro)
# Jump ahead in the MRO to the passed in class
# excluding the last one because that is skipped anyway.
for i in range(0, n - 1):
if mro[i] is su_type:
break
# The C code only increments by one here, but the C for loop
# actually increases the i variable by one before the condition
# is checked so to get the equivalent code one needs to increment
# twice here.
i += 2
# We're at the end of the MRO. Check if super has this attribute.
if i >= n:
return object.__getattribute__(self, name)
# Go up the MRO
while True:
tmp = mro[i]
dict_ = tmp.__dict__
try:
res = dict_[name]
except:
pass
else:
# We found a match, now go through the descriptor protocol
# so that we get a bound method (or whatever is applicable)
# for this attribute.
f = type(res).__get__
f(res, None if su_obj is starttype else su_obj, starttype)
res = tmp
return res
i += 1
# Not really the nicest construct but it's a do-while loop
# in the C code and I feel like this is the closest Python
# representation of that.
if i < n:
continue
else:
break
return object.__getattribute__(self, name)
如您所见,有一些方法可以最终在 super
上查找属性:
- 如果您正在寻找
__class__
属性 - 如果您立即到达 MRO 的末尾(通过将
object
作为第一个参数传递)! - 如果
__getattribute__
在剩余的 MRO 中找不到匹配项。
实际上因为它像 super
一样工作,所以你可以用它代替(至少就属性委托(delegate)而言):
class X(object):
def __init__(self):
print(MySuper(object, self).__repr__())
X()
这将从 MySuper.__repr__
中打印出 hoho
。通过插入一些 print
来跟随控制流,随意试验该代码。
I wonder any reliable material ever mentions it and whether it applies to other Python implementations.
我上面所说的是基于我对 CPython 3.6 源代码的观察,但我认为对于其他 Python 版本应该不会有太大的不同,因为其他 Python 实现(通常)遵循 CPython。
其实我也查过:
并且它们都返回 super
的 __repr__
。
请注意,Python 遵循“我们都是同意的成年人”的风格,所以如果有人费心将这种不寻常 用法形式化,我会感到惊讶。我的意思是谁会尝试委托(delegate)给 object
(“最终”父类)的兄弟类或父类的方法。
关于python - 当类型为 'super()' 时 'object' 的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50656716/