最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Python的方法解析順序(MRO)

 更新時間:2020年03月05日 10:17:04   作者:Daniel2333  
這篇文章主要介紹了淺談Python的方法解析順序(MRO),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

方法解析順序, Method Resolution Order

從一段代碼開始

考慮下面的情況:

class A(object):
 def foo(self):
 print('A.foo()')

class B(object):
 def foo(self):
 print('B.foo()')

class C(B, A):
 pass

c = C()
c.foo()

C同時繼承了類A和類B, 它們都有各自的foo()方法. 那么C的實例c調(diào)用foo()方法時, 到底是調(diào)用A.foo()還是B.foo()?

__mro__

Python的每一個有父類的類都有一個與方法解析順序相關(guān)的特殊屬性:__mro__, 它是一個tuple, 裝著方法解析時的對象查找順序: 越靠前的優(yōu)先級越高. 執(zhí)行下面的代碼:

print type(C.__mro__)
print C.__mro__

輸出:

<type 'tuple'>
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

可以看到, B在C的前面, 所以在上一段代碼中, c.foo()調(diào)用的是B.foo()而不是A.foo().

之所以B在C的前面, 是因為在指定C的父類時先指定了B:

class C(B, A):

若將它改成:

class C(A, B):

c.foo()執(zhí)行的就是A.foo()了.

熟悉環(huán)境變量的可以將__mro__理解為以目標對象為環(huán)境的PATH變量: 從左到右開始查找, 找到就執(zhí)行, 然后返回結(jié)果.

方法解析順序

從C.__mro__的值可以看出, Python的方法解析優(yōu)先級從高到低為:

1. 實例本身(instance)

2. 類(class)

3. super class, 繼承關(guān)系越近, 越先定義, 優(yōu)先級越高.

其實屬性解析順序也基本一致, 只不過多了個__getattr__的查找(見Python對象的屬性訪問過程).

補充知識:python中的單繼承,多繼承和mro順序

python作為一門動態(tài)語言,是和c++一樣支持面向?qū)ο缶幊痰?。相對對象編程有三大特性,分別是繼承,封裝和多態(tài)。今天我們重點講解的是,python語言中的單繼承和多繼承。

繼承概念:

如果一個類繼承了另外一個類時,它將自動獲得另一個類的所有屬性和方法,那么原有的類稱為父類,而新類稱為子類。子類繼承了其父類的所有屬性和方法。同時還可以定義自己的屬性和方法。
單繼承就是一個子類只能繼承一個父類。

格式: class 子類(父類)

舉例: class A(B)

A類擁有了B類的所有的特征,A類繼承了B類

B類 父類,基類

A類 子類 派生類 后代類

繼承的作用:功能的升級和擴展
功能的升級就是對原有 的功能進行完善重新,功能的擴展就是對原本沒有的功能進行添加。減少代碼的冗余。

下面我們舉一個單繼承的例子:

class Dog(): #父類
 def __init__(self): #父類的屬性初始化
 self.name='狗'
 self.leg=4
 def __str__(self):
 return "名字:%s %d 條腿"%(self.name,self.leg)

class Taidi(Dog): #定義一個Taidi 泰迪 類繼承自Dog類 -->單繼承
 pass

taidi=Taidi()
print(taidi) 輸出結(jié)果--> 名字:狗 4 條腿

多繼承:

多繼承就是一個子類同時繼承自多個父類,又稱菱形繼承、鉆石繼承。

首先,我們先講多繼承中一個常見方法,單獨調(diào)用父類的方法。在子類初始化的時候需要手動調(diào)用父類的初始化方法進行父類的屬性的構(gòu)造,不然就不能使用提供的屬性。

在子類中調(diào)用父類的初始化方法格式就是: 父類名._init_(self)

下面舉一個單獨調(diào)用父類方法的例子:

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): #單繼承 Son1子類繼承父類
 def __init__(self, name, age):
 print('Son1的init開始被調(diào)用')
 self.age = age
 Parent.__init__(self, name) #單獨調(diào)用父類的屬性
 print('Son1的init結(jié)束被調(diào)用')

class Son2(Parent): #也是單繼承 Son2繼承父類
 def __init__(self, name, gender):
 print('Son2的init開始被調(diào)用')
 self.gender = gender #單獨調(diào)用父類的初始化屬性方法
 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', 18, '男') #實例化對象
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
年齡: 18
性別: 男
******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******

mro順序

查看上面的運行結(jié)果,我們發(fā)現(xiàn)由于多繼承情況,parent類被的屬性被構(gòu)造了兩次,如果在更加復雜的結(jié)構(gòu)下可能更加嚴重。

為了解決這個問題,Python官方采用了一個算法將復雜結(jié)構(gòu)上所有的類全部都映射到一個線性順序上,而根據(jù)這個順序就能夠保證所有的類都會被構(gòu)造一次。這個順序就是MRO順序。

格式:

類名._mro_()

類名.mro()

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

super本質(zhì)上就是使用MRO這個順序去調(diào)用 當前類在MRO順序中下一個類。 super().init()則調(diào)用了下一個類的初始化方法進行構(gòu)造。

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', 18, '男')
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
年齡: 18
性別: 男
******多繼承使用super().__init__ 發(fā)生的狀態(tài)******

單繼承中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é)果:

******單繼承使用super().__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)用
Grandson的init結(jié)束被調(diào)用
姓名: grandson
年齡: 12
******單繼承使用super().__init__ 發(fā)生的狀態(tài)******

下面讓我們總結(jié)下:

MRO保證了多繼承情況 每個類只出現(xiàn)一次

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

但在多繼承上有區(qū)別,super方法能保證每個父類的方法只會執(zhí)行一次,而使用類名的方法會導致方法被執(zhí)行多次

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

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

多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍,而使用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)

運行結(jié)果:

1 1 1
1 2 1
3 2 3

以上這篇淺談Python的方法解析順序(MRO)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于pyqt5控件自適應窗口超詳細知識點匯總

    關(guān)于pyqt5控件自適應窗口超詳細知識點匯總

    這篇文章主要介紹了關(guān)于pyqt5控件自適應窗口超詳細知識點匯總,有了布局,再在布局中放置各種控件,我們就能讓控件實現(xiàn)自適應的效果,需要的朋友可以參考下
    2023-03-03
  • Python寫的創(chuàng)建文件夾自定義函數(shù)mkdir()

    Python寫的創(chuàng)建文件夾自定義函數(shù)mkdir()

    這篇文章主要介紹了Python寫的創(chuàng)建文件夾自定義函數(shù)mkdir(),文件夾操作是編程中經(jīng)常需要的,mkdir函數(shù)更是經(jīng)典中的經(jīng)典,需要的朋友可以參考下
    2014-08-08
  • python中wheel的用法整理

    python中wheel的用法整理

    在本篇文章里小編給大家整理的是關(guān)于python中wheel的用法整理內(nèi)容,需要的朋友們可以跟著學習下。
    2020-06-06
  • Python開發(fā)裝包八種方法詳解

    Python開發(fā)裝包八種方法詳解

    這篇文章主要為大家介紹了Python開發(fā)中裝包的八種方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-10-10
  • 淺析Python 3 字符串中的 STR 和 Bytes 有什么區(qū)別

    淺析Python 3 字符串中的 STR 和 Bytes 有什么區(qū)別

    Python2的str相當于Python3的Bytes,而Unicode相當于Python3的Bytes。這篇文章主要介紹了Python 3 字符串中的 STR 和 Bytes 究竟有什么區(qū)別?需要的朋友可以參考下
    2018-10-10
  • Python如何用filter函數(shù)篩選數(shù)據(jù)

    Python如何用filter函數(shù)篩選數(shù)據(jù)

    這篇文章主要介紹了Python如何用filter函數(shù)篩選數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • python繪制堆疊條形圖介紹

    python繪制堆疊條形圖介紹

    大家好,本篇文章主要講的是python繪制堆疊條形圖介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • python開啟多個子進程并行運行的方法

    python開啟多個子進程并行運行的方法

    這篇文章主要介紹了python開啟多個子進程并行運行的方法,涉及Python進程操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • python遍歷路徑破解表單的示例

    python遍歷路徑破解表單的示例

    這篇文章主要介紹了python遍歷路徑破解表單的示例,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-11-11
  • Python利用cnocr庫實現(xiàn)pdf文件的文字識別

    Python利用cnocr庫實現(xiàn)pdf文件的文字識別

    很多pdf文件文字識別軟件都會收費,免費的網(wǎng)頁版可能會帶來信息泄露,所以本文為大家介紹了如何利用Python中的cnocr庫完成中文掃描pdf文件的文字識別,需要的可以參考下
    2024-12-12

最新評論

安泽县| 涞源县| 噶尔县| 无极县| 平安县| 响水县| 汉中市| 永安市| 河津市| 邵阳县| 大英县| 凌源市| 犍为县| 资阳市| 祥云县| 宝清县| 化州市| 宁南县| 白银市| 扎鲁特旗| 龙胜| 合肥市| 宝丰县| 孝感市| 定安县| 九寨沟县| 湘潭市| 潜江市| 奉化市| 井冈山市| 阆中市| 广昌县| 靖江市| 翁牛特旗| 威远县| 临澧县| 林西县| 同仁县| 宜阳县| 于田县| 云阳县|