13 Python super

Python 深入理解super的用法

转载请标明出处(http://blog.csdn.net/lis_12/article/details/52870728).

带着问题去学super

Python中既然可以直接通过父类名调用父类的方法为什么还会存在super函数?
比如
class Child(Parent):
def __init__(self):

​ Parent.__init__(self)

这种方式与super(Child, self).__init__()有区别呢?

准备知识:

MRO 全称 Method Resolution Order(方法解析顺序),它代表了类继承的顺序.

注:如果不懂MRO,参考这篇文章(http://blog.csdn.net/lis_12/article/details/52859376)


super()

谨记:super 指的是 MRO 中的下一个类! 不代表父类!!!!!!!

例如:MRO = [A,B,C,D]

super(A,self).__init__()代表A的下一个类B的__init__().

super()的代码实现:

def super(cls, inst):
    mro = inst.__class__.mro()         #获取inst的MRO
    return mro[mro.index(cls) + 1]     #获取cls在MRO中的索引,然后加1

参数说明:

  1. inst 负责生成 MRO 的 list;
  2. 通过 cls 定位当前 MRO 中的 index, 并返回 MRO[index + 1];

这两件事才是 super 的实质,一定要记住!

两种调用父类方法的区别

通过父类名直接调用父类方法

class D(object):
    def __init__(self):
        print 'enter D'
        object.__init__(self)
        print 'leave D'

class C(D):
    def __init__(self):
        print 'enter C'
        D.__init__(self)
        print 'leave C'

class B(D):
    def __init__(self):
        print 'enter B'
        D.__init__(self)
        print 'leave B'

class A(B,C):
    def __init__(self):
        print 'enter A'
        B.__init__(self)
        C.__init__(self)
        print 'leave A'

if __name__ == '__main__':#主程序
    a = A()
    print A.__MRO__
'''
result:
enter A
enter B
enter D
leave D
leave B
enter C
enter D    初始化了两次--!
leave D
leave C
leave A
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <type 'object'>)
'''

super()

#!/usr/bin/python
# -*- coding: utf-8 -*-

class D(object):
    def __init__(self):
        print 'enter D'
        super(D,self).__init__()
        self.x = 'D'
        print 'leave D'

    def fun(self):
        print 'D fun()',self.x

class C(D):
    def __init__(self):
        print 'enter C'
        super(C,self).__init__()
        self.x = 'C'
        print 'leave C'

    def fun(self):
        print 'C fun()',self.x

class B(D):
    def __init__(self):
        print 'enter B'
        super(B,self).__init__()
        print 'leave B'

class A(B,C):
    def __init__(self):
        print 'enter A'
        super(A,self).__init__()
        self.x = 'A'
        print 'leave A'

if __name__ == '__main__':#主程序
    a = A()
    print A.__MRO__
    a.fun()  #按照MRO查找fun()方法,找到后停止查找,self.x = 'A'最后执行的所以self.x = A,如果把self.x = 'A'放到super(A,self).__init__(),self.x = 'C'就是最后执行的喽. 
'''
result:
enter A
enter B
enter C
enter D
leave D             D只初始化一次
leave C
leave B
leave A
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <type 'object'>)
C fun() A
'''

代码说明

通过父类名调用父类中的方法没啥可说的,顺序执行就好,然后就重复调用了父类D的__init__()方法- -!…重点说super.

使用super(A,self).__init__()执行流程:

  1. 首先进入类A的__init__()函数,打印’enter A’,当执行到super处,super(A,self)获取MRO中A的下一个类B,并返回,调用B.__init__();
  2. 进入B.__init__(),打印 ‘enter B’,当执行到super处,super(B,self)获取MRO中B的下一个类C,并返回,调用C.__init__();
  3. 进入C.__init__(),打印 ‘enter C’,当执行到super处,super(C,self)获取MRO中C的下一个类D,并返回,调用D.__init__();
  4. 进入D.__init__(),打印 ‘enter D’,当执行到super处,super(D,self)获取MRO中D的下一个类object,并返回,调用object.__init__();
  5. object.__init__()执行完成后,开始执行D.__init__()->C.__init__()->B.__init__()->A.__init__()中未执行的代码,依次打印leave D C B A;

总结

使用super()优点:

  1. 保证不会重复调用父类的__init__()函数;
  2. 代码更好维护,如果把父类的名字改了以后,使用类名调用方法还需要改类名,代码可维护性太差,使用super则能很好的解决这些问题;

使用super()注意事项:

super要么全用,要么全不用,哪怕父类是object也要用super,千万不要混用.

混用带来的坑:

class D(object):
    def __init__(self):
        print 'enter D'
        super(D,self).__init__()

class C(D):
    def __init__(self):
        print 'enter C'
        super(C,self).__init__()

class B(D):
    def __init__(self):
        print 'enter B'
        D.__init__(self)

class A(B,C):
    def __init__(self):
        print 'enter A'
        super(A,self).__init__()


if __name__ == '__main__':#主程序
    a = A()
    print A.__MRO__
'''
result:
enter A
enter B
enter D
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <type 'object'>)
'''

从以上代码可知,没有调用C的__init__()方法.

__init__()调用顺序:A->B->D->object,绕过了C.

疑问

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Root(object):
    def __init__(self):
        print("this is Root")

class B(Root):
    def __init__(self):
        print("enter B")
        # print(self)  # this will print <__main__.D object at 0x...>
        super(B, self).__init__()
        print("leave B")

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

class D(B, C):
    pass

d = D()
print(d.__class__.__MRO__)
'''
enter A    D中没有重定义__init__()函数是怎么调用的呢?
enter B
enter D
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <type 'object'>)
'''

个人理解:D中默认的__init__()使用了super()……如果有大神知道原因的话求指导,谢谢…

参考网址

  1. https://www.laike9m.com/blog/li-jie-python-super,70/
  2. https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
  3. http://blog.csdn.net/lis_12/article/details/52859376
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值