天天看點

python(一):python進階文法——多繼承以及MRO順序

1. 單獨調用父類的方法

# coding=utf-8

print("******多繼承使用類名.__init__ 發生的狀态******")
class Parent(object):
    def __init__(self, name):
        print('parent的init開始被調用')
        self.name = name
        print('parent的init結束被調用')

class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init開始被調用')
        self.age = age
        Parent.__init__(self, name)
        print('Son1的init結束被調用')

class Son2(Parent):
    def __init__(self, name, gender):
        print('Son2的init開始被調用')
        self.gender = gender
        Parent.__init__(self, name)
        print('Son2的init結束被調用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被調用')
        Son1.__init__(self, name, age)  # 單獨調用父類的初始化方法
        Son2.__init__(self, name, gender)
        print('Grandson的init結束被調用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性别:', gs.gender)

print("******多繼承使用類名.__init__ 發生的狀态******\n\n")
           

運作結果: 

******多繼承使用類名.__init__ 發生的狀态******

Grandson的init開始被調用

Son1的init開始被調用

parent的init開始被調用

parent的init結束被調用

Son1的init結束被調用

Son2的init開始被調用

parent的init開始被調用

parent的init結束被調用

Son2的init結束被調用

Grandson的init結束被調用

姓名: grandson

年齡: 12

性别: 男

******多繼承使用類名.__init__ 發生的狀态******

2. 多繼承中super調用有所父類的被重寫的方法

print("******多繼承使用super().__init__ 發生的狀态******")
class Parent(object):
    def __init__(self, name, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數
        print('parent的init開始被調用')
        self.name = name
        print('parent的init結束被調用')

class Son1(Parent):
    def __init__(self, name, age, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數
        print('Son1的init開始被調用')
        self.age = age
        super().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長參數,接受參數
        print('Son1的init結束被調用')

class Son2(Parent):
    def __init__(self, name, gender, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數
        print('Son2的init開始被調用')
        self.gender = gender
        super().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長參數,接受參數
        print('Son2的init結束被調用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被調用')
        # 多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍
        # 而super隻用一句話,執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因
        # super(Grandson, self).__init__(name, age, gender)
        super().__init__(name, age, gender)
        print('Grandson的init結束被調用')

print(Grandson.__mro__)

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性别:', gs.gender)
print("******多繼承使用super().__init__ 發生的狀态******\n\n")
           

運作結果:

******多繼承使用super().__init__ 發生的狀态******

(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)

Grandson的init開始被調用

Son1的init開始被調用

Son2的init開始被調用

parent的init開始被調用

parent的init結束被調用

Son2的init結束被調用

Son1的init結束被調用

Grandson的init結束被調用

姓名: grandson

年齡: 12

性别: 男

******多繼承使用super().__init__ 發生的狀态******

注意:

  1. 以上2個代碼執行的結果不同
  2. 如果2個子類中都繼承了父類,當在子類中通過父類名調用時,parent被執行了2次
  3. 如果2個子類中都繼承了父類,當在子類中通過super調用時,parent被執行了1次

 3. 單繼承中super

print("******單繼承使用super().__init__ 發生的狀态******")
class Parent(object):
    def __init__(self, name):
        print('parent的init開始被調用')
        self.name = name
        print('parent的init結束被調用')

class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init開始被調用')
        self.age = age
        super().__init__(name)  # 單繼承不能提供全部參數
        print('Son1的init結束被調用')

class Grandson(Son1):
    def __init__(self, name, age, gender):
        print('Grandson的init開始被調用')
        super().__init__(name, age)  # 單繼承不能提供全部參數
        print('Grandson的init結束被調用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年齡:', gs.age)
#print('性别:', gs.gender)
print("******單繼承使用super().__init__ 發生的狀态******\n\n")
print(Grandson.__mro__)
           

******單繼承使用super().__init__ 發生的狀态******Grandson的init開始被調用

Son1的init開始被調用

parent的init開始被調用

parent的init結束被調用

Son1的init結束被調用

Grandson的init結束被調用

姓名: grandson

年齡: 12

******單繼承使用super().__init__ 發生的狀态******

(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Parent'>, <class 'object'>)

總結

  1. super().__init__相對于 類名.__init__,在單繼承上用法基本無差
  2. 但在多繼承上有差別,super方法能保證每個父類的方法隻會執行一次,而使用類名的方法會導緻父類方法被執行多次,具體看前面的輸出結果
  3. 多繼承時,使用super方法,對父類的傳參數,應該是由于python中super的算法導緻的原因,必須把參數全部傳遞,否則會報錯
  4. 單繼承時,使用super方法,則不能全部傳遞,隻能傳父類方法所需的參數,否則會報錯
  5. 多繼承時,相對于使用 類名.__init__方法,要把每個父類全部寫一遍, 而使用super方法,隻需寫一句話便執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因