Python的mro

一个python的super和mro问题今天让我纠结了一早上,源自于看tornado的源代码对于super这个“方法”产生的困惑,对于老鸟mro应该是常识了,对于小白而言,尼玛搞懂这个掉了我好几根头发。

 

谷歌了一下找到一篇博客也在讨论这个问题,博主列举了一个例子我觉得很典型,同时他也提出了和我一样的问题,我在原文的引用中高亮了。下面摘自“JohnsonGuo的专栏”

 

 

有一天某同事设计了一个相对复杂的类体系结构(我们先不要管这个类体系设计得是否合理,仅把这个例子作为一个题目来研究就好),代码如代码段4:

 代码段4:

 class A(object):
  def __init__(self):
   print "enter A"
   print "leave A"

 class B(object):
  def __init__(self):
   print "enter B"
   print "leave B"

 class C(A):
  def __init__(self):
   print "enter C"
   super(C, self).__init__()
   print "leave C"

 class D(A):
  def __init__(self):
   print "enter D"
   super(D, self).__init__()
   print "leave D"
 class E(B, C):
  def __init__(self):
   print "enter E"
   B.__init__(self)
   C.__init__(self)
   print "leave E"

 class F(E, D):
  def __init__(self):
   print "enter F"
   E.__init__(self)
   D.__init__(self)
   print "leave F"

 >>> f = F()

 enter F
 enter E
 enter B
 leave B
 enter C
 enter D
 enter A
 leave A
 leave D
 leave C
 leave E
 enter D
 enter A
 leave A
 leave D
 leave F

  明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:

  

 

  按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!

 

作者翻阅python源代码后得出的结论对我非常有帮助,同样摘抄如下,感谢JohnsonGuo的分享:

 

  1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,

       产生了一个super对象;
  2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
  3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
  4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
       只调用一次(如果每个类都使用super);
  5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
       个父类函数被调用多次。

 

 

顺着作者的结论我想补充一条:

如作者所说super并不是像我们想象中一样直接找到当前类的父类,而是沿着mro顺藤摸瓜,所以有可能出现作者原文中提到的问题!

 

补充阅读:

对于想要了解更多细节而不愿意翻阅Python源码的人(比如我。。),强烈推荐阅读Python的这篇文档:“The Python 2.3 Method Resolution Order”,看下来试下来,基本就了解的八九不离十了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值