python之super()函数 #单类继承&多类继承 #super()使用debug过程

描述

super() 函数是用于调用父类(超类)的一个方法。

super 是用来解决多重继承问题的。(当然,单继承也可以用。)

多重继承,也就是我们可以为一个类同时指定多个父类。

直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
钻石继承例如:

      Base
      /  \
     /    \
    A      B
     \    /
      \  /
       C

语法

super(type[, object-or-type])

  • type:类。
  • object-or-type:类,一般是 self

python2和python3使用super()区别

python3.x 和 python2.x 的一个区别是:
python3 可以使用直接使用 super().xxx代替 super(Class, self).xxx

class A:
     def add(self, x):
         y = x+1
         print(y)
class B(A):
    def add(self, x):
        super().add(x)   # python2.x:super(B, self).add(x)
b = B()
b.add(2)  # 3

super()单类继承

在单类继承中,其意义就是不需要父类的名称来调用父类的函数,因此当子类改为继承其他父类的时候,不需要对子类内部的父类调用函数做任何修改就能调用新父类的方法。

# 定义父类base1                      # 定义父类base2
class base1(object):                # class base2(object):
    def __init__(self):             #    def __init__(self): 
        print("base1 class")        #        print("base2 class")

# 不使用super(),若继承父类base2,需要修改内部的父类调用函数,都换成base2
class A(base1):                     # class A(base2):
    def __init__(self):             #     def __init__(self):
        base1.__init__(self)        #         base2.__init__(self)    

# 使用super(),只需要修改类的定义,第一行
class B(base1):                     # class B(base2):
    def __init__(self):             #     def __init__(self):
        super(B, self).__init__()   #         super(B, self).__init__()

这里要注意的是

  • base1.__init__(self)vs.super(B, self).__init__(),后者:由于super将传入self作为调用__init__默认的第一个变量,因此在声明的时候不需要显式表示self。
  • 此外由于super返回的是代理对象,因此父类只能调用一次,也就避免了如下异常的可能性。
base1 = A
base1()    # 无限递归

super()多类继承

在多类继承中super()是必不可少的(多类继承是python的一大特色)。

super()的__mro__变量记录了方法解析搜索顺序,即一个类的所有父类的调用顺序(MRO用来保证多类继承的时候各父类被逐一调用并只被调用一次)。

# -*- coding: UTF-8 -*-

# 定义父类base1
class base1(object):
    def __init__(self):
        pass

# 定义子类B继承父类base1
class B(base1):
    def __init__(self):
        super(B, self).__init__()
        
# 定义子类mixin继承父类base1
class mixin(base1):
    def __init__(self):
        super(mixin, self).__init__()

class C(B, mixin):    # 1. mixin类插入到了B类和base1类之间
    pass

if __name__ == '__main__':
    C()
    print(C.__mro__)   # 2. 方法解析顺序(MRO): C -> B -> mixin -> base1

在上述调用中,base1类不再是C类实例中B类的父类。
如果self是C类实例,super(B, self)将指向mixin类。

执行结果:
在这里插入图片描述

一个简单的代码示例

class A:
    def func(self):
        print('OldBoy')


class B(A):
    def func(self):
        super().func()
        print('LuffyCity')

A().func()
B().func()

A实例化的对象调用了func方法,打印输出了 Oldboy;
B实例化的对象调用了自己的func方法,先调用了父类的方法打印输出了 OldBoy ,再打印输出 LuffyCity 。

输出结果为:
在这里插入图片描述

super()使用debug过程

# -*- coding: UTF-8 -*-

class FooParent(object):
    def __init__(self):
        self.parent = 'I\'m the parent.'

    def bar(self, message):
        print("%s from Parent" % message)


class FooChild(FooParent):
    def __init__(self):
        # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),
        # 然后把类 FooChild 的对象转换为类 FooParent 的对象
        super(FooChild, self).__init__()

    def bar(self, message):
        super(FooChild, self).bar(message)
        print(self.parent)


if __name__ == '__main__':
    fooChild = FooChild()
    fooChild.bar('HelloWorld')

(1)执行fooChild = FooChild()过程
执行fooChild = FooChild()调用class FooChild(FooParent)类,

  • 先执行super(FooChild, self).__init__():首先找到 FooChild 的父类(就是class FooParent),然后self.parent = 'I\'m the parent.'把类 FooChild 的对象转换为类 FooParent 的对象。

(2)继续执行fooChild.bar(‘HelloWorld’)过程
执行fooChild.bar('HelloWorld')调用class FooChild的bar函数,

  • 先执行super(FooChild, self).bar(message):首先找到 FooChild 的父类(就是class FooParent),然后调用父类里的bar函数,传入参数message='HelloWorld',执行print("%s from Parent" % message),执行完这里输出【HelloWorld from Parent】
  • 然后执行print(self.parent),执行完这里输出【I’m the parent.】,因为(1)中已经把类 FooChild 的对象转换为类 FooParent 的对象。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章