在一般情况下,Python的super()实际上是如何工作的?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了在一般情况下,Python的super()实际上是如何工作的?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3289字,纯文字阅读大概需要5分钟。
内容图文
![在一般情况下,Python的super()实际上是如何工作的?](/upload/InfoBanner/zyjiaocheng/750/c96901697a4d400798130e09e684c9ea.jpg)
super()上有很多很棒的资源,包括this个很棒的博客帖子,以及Stack Overflow上的很多问题.但是我觉得他们都没有解释它在最常见的情况下是如何工作的(使用任意继承图),以及在幕后发生的事情.
考虑这个钻石继承的基本例子:
class A(object):
def foo(self):
print 'A foo'
class B(A):
def foo(self):
print 'B foo before'
super(B, self).foo()
print 'B foo after'
class C(A):
def foo(self):
print 'C foo before'
super(C, self).foo()
print 'C foo after'
class D(B, C):
def foo(self):
print 'D foo before'
super(D, self).foo()
print 'D foo after'
如果您从this等来源阅读Python的方法解析顺序规则或查找wikipedia page的C3线性化,您将看到MRO必须是(D,B,C,A,对象).这当然是由D .__ mro__确认的:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
和
d = D()
d.foo()
版画
D foo before
B foo before
C foo before
A foo
C foo after
B foo after
D foo after
哪个与MRO相匹配.但是,考虑到B中的super(B,self).foo()实际上调用C.foo,而b = B(); b.foo()它会直接转到A.foo.显然,使用super(B,self).foo()不仅仅是A.foo(self)的捷径,有时候也是如此.
然后,super()显然知道之前的调用以及链条试图遵循的整个MRO.我可以看到两种方法可以完成.第一种方法是将超级对象本身作为自身参数传递给链中的下一个方法,它将像原始对象一样运行,但也包含此信息.然而,这似乎也会破坏很多东西(超级(D,d)是d是假的)并且通过做一些实验我可以看到情况并非如此.
另一种选择是使用某种全局上下文来存储MRO及其当前位置.我认为super的算法类似于:
>目前我们正在开展工作吗?如果没有,请创建一个包含队列的.获取类参数的MRO,将除第一个元素之外的所有元素推入队列.
>从当前上下文的MRO队列中弹出下一个元素,在构造超级实例时将其用作当前类.
>从超级实例访问方法时,在当前类中查找并使用相同的上下文调用它.
但是,这并不能解释奇怪的事情,比如使用不同的基类作为调用super的第一个参数,甚至调用不同的方法.我想知道这个的一般算法.此外,如果这种情况存在于某处,我可以检查它吗?我可以捣蛋吗?当然可怕的想法,但Python通常希望你成为一个成熟的成年人,即使你不是.
这也引入了许多设计考虑因素.如果我写B只考虑它与A的关系,那么后来有人写C并且第三个人写D,我的B.foo()方法必须以与C.foo()兼容的方式调用super,即使它在我写的时候不存在!如果我希望我的类可以轻松扩展,我将需要考虑到这一点,但我不确定它是否比简单地确保所有版本的foo具有相同的签名更复杂.还有一个问题是何时在调用super之前或之后放置代码,即使它只考虑B的基类没有任何区别.
解决方法:
super() is then obviously aware of the previous calls before it
不是.当你做超级(B,自我).foo时,超级知道MRO,因为那只是类型(自我).__ mro__,并且它知道它应该在B之后立即开始在MRO中寻找foo.粗略的纯粹 – Python等价物
class super(object):
def __init__(self, klass, obj):
self.klass = klass
self.obj = obj
def __getattr__(self, attrname):
classes = iter(type(self.obj).__mro__)
# search the MRO to find self.klass
for klass in classes:
if klass is self.klass:
break
# start searching for attrname at the next class after self.klass
for klass in classes:
if attrname in klass.__dict__:
attr = klass.__dict__[attrname]
break
else:
raise AttributeError
# handle methods and other descriptors
try:
return attr.__get__(self.obj, type(self.obj))
except AttributeError:
return attr
If I wrote B thinking only of its relation to A, then later someone else writes C and a third person writes D, my B.foo() method has to call super in a way that is compatible with C.foo() even though it didn’t exist at the time I wrote it!
没有任何期望你应该能够从任意类中多次继承.除非foo专门设计为在多继承情况下被兄弟类重载,否则D不应该存在.
内容总结
以上是互联网集市为您收集整理的在一般情况下,Python的super()实际上是如何工作的?全部内容,希望文章能够帮你解决在一般情况下,Python的super()实际上是如何工作的?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。