溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Python項目中使用MRO順序

發(fā)布時間:2021-03-23 15:42:33 來源:億速云 閱讀:180 作者:Leah 欄目:開發(fā)技術

本篇文章給大家分享的是有關如何在Python項目中使用MRO順序,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

多繼承以及MRO順序

1. 單獨調(diào)用父類的方法

# coding=utf-8

print("******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******")
class Parent(object):
 def __init__(self, name):
  print('parent的init開始被調(diào)用')
  self.name = name
  print('parent的init結(jié)束被調(diào)用')

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

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

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

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

print("******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******\n\n")

運行結(jié)果:

******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******
Grandson的init開始被調(diào)用
Son1的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son1的init結(jié)束被調(diào)用
Son2的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son2的init結(jié)束被調(diào)用
Grandson的init結(jié)束被調(diào)用
姓名: grandson
年齡: 12
性別: 男
******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******

2. 多繼承中super調(diào)用有所父類的被重寫的方法

print("******多繼承使用super().__init__ 發(fā)生的狀態(tài)******")
class Parent(object):
 def __init__(self, name, *args, **kwargs): # 為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)
  print('parent的init開始被調(diào)用')
  self.name = name
  print('parent的init結(jié)束被調(diào)用')

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

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

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

print(Grandson.__mro__)

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

運行結(jié)果:

******多繼承使用super().__init__ 發(fā)生的狀態(tài)******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init開始被調(diào)用
Son1的init開始被調(diào)用
Son2的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son2的init結(jié)束被調(diào)用
Son1的init結(jié)束被調(diào)用
Grandson的init結(jié)束被調(diào)用
姓名: grandson
年齡: 12
性別: 男
******多繼承使用super().__init__ 發(fā)生的狀態(tài)******

注意:

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

3. 單繼承中super

print("******單繼承使用super().__init__ 發(fā)生的狀態(tài)******")
class Parent(object):
 def __init__(self, name):
  print('parent的init開始被調(diào)用')
  self.name = name
  print('parent的init結(jié)束被調(diào)用')

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

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

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年齡:', gs.age)
#print('性別:', gs.gender)
print("******單繼承使用super().__init__ 發(fā)生的狀態(tài)******\n\n")

總結(jié)

  1. super().__init__相對于類名.init,在單繼承上用法基本無差

  2. 但在多繼承上有區(qū)別,super方法能保證每個父類的方法只會執(zhí)行一次,而使用類名的方法會導致方法被執(zhí)行多次,具體看前面的輸出結(jié)果

  3. 多繼承時,使用super方法,對父類的傳參數(shù),應該是由于python中super的算法導致的原因,必須把參數(shù)全部傳遞,否則會報錯

  4. 單繼承時,使用super方法,則不能全部傳遞,只能傳父類方法所需的參數(shù),否則會報錯

  5. 多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍,

  6. 而使用super方法,只需寫一句話便執(zhí)行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因

小試牛刀(以下為面試題)

以下的代碼的輸出將是什么? 說出你的答案并解釋。

class Parent(object):
 x = 1

class Child1(Parent):
 pass

class Child2(Parent):
 pass

print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)

答案, 以上代碼的輸出是:

使你困惑或是驚奇的是關于最后一行的輸出是 3 2 3 而不是 3 2 1。為什么改變了 Parent.x 的值還會改變 Child2.x
的值,但是同時 Child1.x 值卻沒有改變?

這個答案的關鍵是,在 Python中,類變量在內(nèi)部是作為字典處理的。如果一個變量的名字沒有在當前類的字典中發(fā)現(xiàn),將搜索祖先類(比如父類)直到被引用的變量名被找到(如果這個被引用的變量名既沒有在自己所在的類又沒有在祖先類中找到,會引發(fā)一個 AttributeError 異常 )。

因此,在父類中設置 x = 1 會使得類變量 x 在引用該類和其任何子類中的值為 1。這就是因為第一個 print 語句的輸出是 1 1 1。
隨后,如果任何它的子類重寫了該值(例如,我們執(zhí)行語句 Child1.x = 2),然后,該值僅僅在子類中被改變。這就是為什么第二個print 語句的輸出是 1 2 1。

最后,如果該值在父類中被改變(例如,我們執(zhí)行語句 Parent.x =
3),這個改變會影響到任何未重寫該值的子類當中的值(在這個示例中被影響的子類是 Child2)。這就是為什么第三個 print 輸出是 3 2 3。

以上就是如何在Python項目中使用MRO順序,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學到更多知識。更多詳情敬請關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI