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

詳析Python面向?qū)ο笾械睦^承

 更新時(shí)間:2022年03月07日 11:11:37   作者:搬磚,贊路費(fèi)  
這篇文章主要詳析Python面向?qū)ο笾械睦^承,類繼承作為python的三大特性之一,在我們學(xué)習(xí)python的時(shí)候是必不可少的。使用類繼承,能夠大大減少重復(fù)代碼的編寫,下文詳細(xì)內(nèi)容需要的小伙伴可以參考一下

一 單繼承

類繼承作為python的三大特性之一,在我們學(xué)習(xí)python的時(shí)候是必不可少的。使用類繼承,能夠大大減少重復(fù)代碼的編寫?,F(xiàn)來記錄下,python中關(guān)于類繼承的一些知識(shí)點(diǎn)。
類的繼承有單繼承,多層繼承以及多重繼承,先來看看單繼承。

1. 繼承的基本語法格式如下

#類繼承語法格式,B類繼承A類
class A():
? ? 類屬性
? ? 類方法
? ? ...
class B(A):
? ? 類屬性
? ? 類方法
? ? ...

單繼承的話一般類A是沒有繼承其他派生類的,只繼承了基類。因?yàn)樵趐ython新式類中,一個(gè)類會(huì)默認(rèn)去繼承基類object的,基類object是頂級(jí)類。

2. 查看類繼承情況

class Father():
? ? #這是父類
? ? name1 = 'father_name'
? ? age1 = 'father_age'
? ? def father_method(self):
? ? ? ? print('我是父親')

class Son(Father):
? ? #這是子類
? ? name2 = 'son_name'
? ? age2 = 'son_age'
? ? def son_method(self):
? ? ? ? print('我是孩子')

if __name__ == '__main__':
? ? A = Father()
? ? B = Son()
? ? #單繼承
? ? print(B.__class__.__mro__)
? ? #或者Son.mro()
? ? print(Son.mro())

如上:我們定義了一個(gè)父類Father,一個(gè)子類Son,并且子類Son繼承父類Father,它們都有自己的屬性和方法。我們可以通過打印B.__ class__.__mro __ 或者Son.mro()來查看Son類的繼承情況,如下:

>>>
(<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>)
[<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>]

可以看到,Son類確實(shí)繼承了Father類,并且繼承基類object。

3. 繼承中的屬性和方法

如果一個(gè)類繼承了另外一個(gè)類,那么這個(gè)類是可以調(diào)用其繼承類的屬性和方法的(子類可以調(diào)用父類的屬性和方法),如下

class Father():
? ? #這是父類
? ? name1 = 'father_name'
? ? age1 = 'father_age'
? ? def father_method(self):
? ? ? ? print('我是父親')

class Son(Father):
? ? #這是子類
? ? name2 = 'son_name'
? ? age2 = 'son_age'
? ? def son_method(self):
? ? ? ? print('我是孩子')

? ? def fun1(self):
? ? ? ? #調(diào)用父類屬性和方法
? ? ? ? print(self.age1, self.name1)
? ? ? ? self.father_method()

if __name__ == '__main__':
? ? A = Father()
? ? B = Son()
? ? #單繼承
? ? # print(B.__class__.__mro__)
? ? B.fun1()

結(jié)果如下:

>>>
father_age father_name
我是父親

當(dāng)子類中的屬性名方法名和父類中的屬性名方法名同名時(shí),在該子類中會(huì)覆蓋父類的屬性名和方法名(重寫)。

class Father():
? ? #這是父類
? ? name1 = 'father_name'
? ? age1 = 'father_age'
? ? def father_method(self):
? ? ? ? print('我是父親')

class Son(Father):
? ? #這是子類
? ? name1 = 'son_name'
? ? age1 = 'son_age'
? ? def son_method(self):
? ? ? ? print('我是孩子')

? ? def father_method(self):
? ? ? ? #和父類方法同名,將以子類方法為準(zhǔn)
? ? ? ? print("與父類方法同名,但是我是子類")

? ? def son_fun1(self):
? ? ? ? #調(diào)用父類屬性
? ? ? ? print("子類屬性和父類屬性同名,以子類為準(zhǔn):", self.name1, self.age1)


if __name__ == '__main__':
? ? A = Father()
? ? B = Son()
? ? #單繼承
? ? # print(B.__class__.__mro__)
? ? B.father_method()
? ? B.son_fun1()

輸出如下:

>>>
與父類方法同名,但是我是子類
子類屬性和父類屬性同名,以子類為準(zhǔn): son_name son_age

4. 初始化函數(shù)__init__()和 super

上面寫的子類和父類都是不需要傳參數(shù)的,而當(dāng)我們需要給類傳參數(shù)時(shí),往往都是要初始化的,下面來看看子類繼承父類時(shí),參數(shù)初始化的幾種情況。

子類無新增參數(shù):

class Father():
? ? #父類
? ? def __init__(self, name='張三', age=23):
? ? ? ? self.name = name
? ? ? ? self.age = age

class Son(Father):
? ? #子類
? ? def son_fun1(self):
? ? ? ? print(self.name, self.age)

if __name__ == '__main__':
? ? B = Son()
? ? B.son_fun1()

輸出:

>>>
張三 23

如上,在子類無新增參數(shù)時(shí),無需進(jìn)行__init__ 初始化,直接調(diào)用父類的對(duì)象屬性即可。因?yàn)樽宇怱on是繼承自父類Father的,所以在調(diào)用時(shí)會(huì)首先去調(diào)父類的__init__ 進(jìn)行初始化

子類有新增參數(shù):

當(dāng)子類有新增參數(shù)時(shí),該怎么初始化呢?先來看看這個(gè)對(duì)不對(duì)

class Father():
? ? #父類
? ? def __init__(self, name='張三', age=23):
? ? ? ? self.name = name
? ? ? ? self.age = age

class Son(Father):
? ? #子類
? ? def __init__(self, height):
? ? ? ? self.height = height

? ? def son_fun1(self):
? ? ? ? print(self.height)
? ? ? ? print(self.name, self.age)

if __name__ == '__main__':
? ? B = Son(170)
? ? B.son_fun1()

輸出:

>>>
AttributeError: 'Son' object has no attribute 'name'
170

上面子類Son新增了一個(gè)height參數(shù),然后用__init__ 進(jìn)行初始化。但是從輸出結(jié)果可以看出,height參數(shù)是正常打印的,打印name和age參數(shù)時(shí)就報(bào)錯(cuò):子類Son沒有屬性’name’,因?yàn)檫@個(gè)時(shí)候就不會(huì)去調(diào)用父類的__init__ 進(jìn)行初始化,而是直接調(diào)用子類中的__init__ 進(jìn)行初始化,這時(shí),子類初始化就會(huì)覆蓋掉父類的__init__ 初始化,從而報(bào)錯(cuò)。

正確的初始化有兩種方法,如下:

#方法1
def __init__(self, 父類參數(shù)1, 父類參數(shù)2, ..., 子類參數(shù)1, 子類參數(shù)2, ...)
?? ?父類名.__init__(self, 父類參數(shù)1, 父類參數(shù)2, ...)
?? ?self.子類屬性 = 子類屬性

class Father():
? ? #父類
? ? def __init__(self, name='張三', age=23):
? ? ? ? self.name = name
? ? ? ? self.age = age

class Son(Father):
? ? #子類
? ? def __init__(self, name, age, height):
? ? ? ? #方法1
? ? ? ? Father.__init__(self, name, age)
? ? ? ? self.height = height

? ? def son_fun1(self):
? ? ? ? print(self.height)
? ? ? ? print(self.name, self.age)

if __name__ == '__main__':
? ? B = Son('李四', 24, 170)
? ? B.son_fun1()

>>>
175
李四 24

從結(jié)果可以看出,調(diào)用父類初始化后,結(jié)果就正常輸出。這是在子類__init__初始化的時(shí)候,調(diào)用了Father.__ init __(self, name, age)對(duì)父類對(duì)象屬性進(jìn)行了初始化。

現(xiàn)在來看看另外一個(gè)初始化方法super()初始化,不過使用super()的時(shí)候要注意python的版本,因?yàn)閜ython2和python3的使用是不同的,如下

#方法2
def __init__(self, 父類參數(shù)1, 父類參數(shù)2, ..., 子類參數(shù)1, 子類參數(shù)2, ...):?
? ? #python2的super初始化
? ? super(子類名, self).__init__(父類類參數(shù)1, 父類參數(shù)2, ...)
? ? self.子類屬性 = 子類屬性
? ? #python3的super初始化
? ? super().__init__(父類類參數(shù)1, 父類參數(shù)2, ...)
? ? self.子類屬性 = 子類屬性


class Father():
? ? #父類
? ? def __init__(self, name='張三', age=23):
? ? ? ? self.name = name
? ? ? ? self.age = age

class Son(Father):
? ? #子類
? ? def __init__(self, name, age, height):
? ? ? ? #方法2
? ? ? ? #python2的super初始化
? ? ? ? super(Son, self).__init__(name, age)
? ? ? ? self.height = height
? ? ? ? #python3的super初始化
? ? ? ? # super().__init__(name, age)
? ? ? ? #或者 super(Son, self).__init__(name, age)
? ? ? ??
? ? def son_fun1(self):
? ? ? ? print(self.height)
? ? ? ? print(self.name, self.age)

if __name__ == '__main__':
? ? B = Son('李四', 24, 175)
? ? B.son_fun1()

結(jié)果:

>>>
175
李四 24

上面使用的是super(Son, self).__ init __ (name, age) 來對(duì)父類對(duì)象屬性進(jìn)行初始化。不過這是要區(qū)分python版本的,在python3中使用super(Son, self).__ init__(name, age)或者super().__ init__(name, age)都是可以的,但是在python2的版本中,要使用super(Son, self).__ init__(name, age)來進(jìn)行初始化,而且父類必須繼承object,否則就會(huì)報(bào)錯(cuò)。

二 多層繼承

上面的記錄的是單繼承,現(xiàn)在來看看多層繼承。多層繼承:子類繼承自多個(gè)父類,父類只繼承自object頂級(jí)類。

class Father():
? ? def __init__(self):
? ? ? ? print("enter father")
? ? ? ? print("leave father")

? ? def fun(self):
? ? ? ? print("這是father")

class Mother():
? ? def __init__(self):
? ? ? ? print("enter mother")
? ? ? ? print("leave mother")

? ? def fun(self):
? ? ? ? print("這是mather")

class Son(Father, Mother):
? ? def __init__(self):
? ? ? ? print("enter son")
? ? ? ? super().__init__()
? ? ? ? print("leave son")

if __name__ == '__main__':
? ? B = Son()
? ? B.fun()
? ? print(Son.mro())

輸出:

>>>
enter son
enter father
leave father
leave son
這是father

繼承關(guān)系:

[<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>]

這里有兩個(gè)父類Father,Mother,一個(gè)子類Son,子類Son繼承了類Father和Mother,繼承順序是Father在前,Mother在后。從上面輸出結(jié)果來看,子類初始化過程是先進(jìn)入子類Son的 __ init __方法,其次調(diào)用super(). __init __()進(jìn)行父類對(duì)象屬性初始化,最后初始化完成。
從結(jié)果可以知道上面super初始化調(diào)用的是父類Father的 __ init __方法。
。也可以看出,類Father和類Mother都有一個(gè)fun方法(同名),但在子類調(diào)用時(shí)調(diào)的是父類father的fun方法。這是為什么呢?

這里就涉及到super的繼承機(jī)制,即super會(huì)根據(jù)MRO機(jī)制,從左到右依次調(diào)用父類的屬性和方法, 當(dāng)父類中有同屬性名,同方法名時(shí),以靠左的那個(gè)父類為準(zhǔn)。

下面我們把Father和Mother位置換一下,如下:

class Father():
? ? def __init__(self):
? ? ? ? print("enter father")
? ? ? ? print("leave father")

? ? def fun(self):
? ? ? ? print("這是father")

class Mother():
? ? def __init__(self):
? ? ? ? print("enter mother")
? ? ? ? print("leave mother")

? ? def fun(self):
? ? ? ? print("這是mather")

class Son(Mother, Father):#這里變動(dòng),變換Father和Mother的位置
? ? def __init__(self):
? ? ? ? print("enter son")
? ? ? ? super().__init__()
? ? ? ? print("leave son")

if __name__ == '__main__':
? ? B = Son()
? ? B.fun()
? ? print(Son.mro())

結(jié)果:

>>>
enter son
enter mother
leave mother
leave son
這是mather
[<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]

繼承關(guān)系:

>>>
[<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]

可以看出,當(dāng)Mother在前時(shí),調(diào)用的就是類Mather的初始化方法和fun方法。所以在多層繼承時(shí),一定要注意父類的位置順序。

三 多重繼承

其實(shí)super的產(chǎn)生就是用來解決多重繼承問題的,什么是多重繼承呢?即,子類繼承多個(gè)父類,而父類又繼承自其它相同的類,這種又被稱為菱形繼承或者磚石繼承,

如下:

     A
   /   \
  /     \
 B       C
  \     /
   \   /
     D

先來看看如下的一個(gè)菱形繼承:

class A():
? ? def __init__(self):
? ? ? ? print("enter A")
? ? ? ? print("leave A")

class B(A):
? ? def __init__(self):
? ? ? ? print("enter B")
? ? ? ? # super().__init__()
? ? ? ? A.__init__(self)
? ? ? ? print("leave B")

class C(A):
? ? def __init__(self):
? ? ? ? print("enter C")
? ? ? ? # super().__init__()
? ? ? ? A.__init__(self)
? ? ? ? print("leave C")

class D(B, C):
? ? def __init__(self):
? ? ? ? print("enter D")
? ? ? ? B.__init__(self)
? ? ? ? C.__init__(self)
? ? ? ? # super().__init__()
? ? ? ? print("leave D")

if __name__ == '__main__':
? ? d = D()

輸出結(jié)果:

>>>
enter D
enter B
enter A
leave A
leave B
enter C
enter A
leave A
leave C
leave D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

上面用的是父類名. __ init__ () 來進(jìn)行子類初始化的,但是從結(jié)果來看,類A的初始化方法是被執(zhí)行了兩次的,一次是類B的調(diào)用,一次是類C的調(diào)用。也可以看出子類D的初始化 __ init __ 調(diào)用了B.__ init __() 和C. __init __() ?,F(xiàn)在D類繼承的父類只有B和C,但是當(dāng)代碼比較復(fù)雜,繼承的類比較多時(shí),就得的一個(gè)一個(gè)寫,如果類B和類C也是繼承自多個(gè)類,那它們的初始化方法也得重新寫,這樣就比較繁瑣,也容易出錯(cuò)。

下面來使用super初始化父類看看:

class A():
? ? def __init__(self):
? ? ? ? print("enter A")
? ? ? ? print("leave A")

class B(A):
? ? def __init__(self):
? ? ? ? print("enter B")
? ? ? ? super().__init__()
? ? ? ? print("leave B")

class C(A):
? ? def __init__(self):
? ? ? ? print("enter C")
? ? ? ? super().__init__()
? ? ? ? print("leave C")

class D(B, C):
? ? def __init__(self):
? ? ? ? print("enter D")
? ? ? ? super().__init__()
? ? ? ? print("leave D")

if __name__ == '__main__':
? ? d = D()
? ? print(D.mro())

輸出結(jié)果:

enter D
enter B
enter C
enter A
leave A
leave C
leave B
leave D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

可以看到輸出結(jié)果是不一樣的,類A的初始化只執(zhí)行了一次,而且當(dāng)D類有新增父類時(shí),初始化方法也不用動(dòng),從而避免重寫初始化方法出錯(cuò),代碼也變得整潔。
這里還是和super的繼承機(jī)制有關(guān),上面說過當(dāng)子類繼承自多個(gè)父類時(shí),super會(huì)根據(jù)MRO機(jī)制,從左到右依次調(diào)用父類的屬性和方法,而且使用super初始化父類時(shí),會(huì)一次性初始化所有的父類,所以上面的類A初始化方法不會(huì)被調(diào)用兩次。

所以在類的多重繼承中,一般建議使用super來初始化父類對(duì)象屬性。

到此這篇關(guān)于詳析Python面向?qū)ο笾械睦^承的文章就介紹到這了,更多相關(guān)Python面向?qū)ο罄^承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python使用正則表達(dá)式替換匹配成功的組并輸出替換的次數(shù)

    python使用正則表達(dá)式替換匹配成功的組并輸出替換的次數(shù)

    正則表達(dá)式是一個(gè)特殊的字符序列,它能幫助你方便的檢查一個(gè)字符串是否與某種模式匹配。這篇文章主要介紹了python使用正則表達(dá)式替換匹配成功的組并輸出替換的次數(shù),需要的朋友可以參考下
    2017-11-11
  • 詳解運(yùn)行Python的神器Jupyter Notebook

    詳解運(yùn)行Python的神器Jupyter Notebook

    如果我們想要運(yùn)行Python,就是在Python或者IPython的解釋器環(huán)境中進(jìn)行交互式運(yùn)行,或者程序員最喜歡的編寫.py文件,在文件中編寫python代碼,然后運(yùn)行。如果想寫一篇Python的文章,里面有代碼,還希望代碼在當(dāng)前頁面運(yùn)行,那就是使用我們今天要介紹的Jupyter Notebook。
    2021-06-06
  • 深入學(xué)習(xí)Python中的裝飾器使用

    深入學(xué)習(xí)Python中的裝飾器使用

    @這個(gè)操作符讓裝飾器在Python代碼中非常醒目,而裝飾器的運(yùn)用中也包含著很多Python編程中的高級(jí)技巧,這里我們就來共同深入學(xué)習(xí)Python中的裝飾器使用
    2016-06-06
  • 對(duì)numpy中的where方法嵌套使用詳解

    對(duì)numpy中的where方法嵌套使用詳解

    今天小編就為大家分享一篇對(duì)numpy中的where方法嵌套使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • python 中的列表生成式、生成器表達(dá)式、模塊導(dǎo)入

    python 中的列表生成式、生成器表達(dá)式、模塊導(dǎo)入

    這篇文章主要介紹了python中的列表生成式、生成器表達(dá)式、模塊導(dǎo)入 ,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • Python字典的核心底層原理講解

    Python字典的核心底層原理講解

    今天小編就為大家分享一篇關(guān)于Python字典的核心底層原理講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Python?列表中的刪除操作之del、remove?和?pop?的區(qū)別

    Python?列表中的刪除操作之del、remove?和?pop?的區(qū)別

    在Python中,列表(list)是一種非常靈活的數(shù)據(jù)結(jié)構(gòu),它允許我們存儲(chǔ)一系列的元素,在刪除元素時(shí),我們可以使用三種不同的方法:del、remove?和?pop,每種方法都有其特定的用途和行為,了解它們的區(qū)別可以幫助我們更有效地使用列表,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • Python獲取指定字符前面的所有字符方法

    Python獲取指定字符前面的所有字符方法

    下面小編就為大家分享一篇Python獲取指定字符前面的所有字符方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python應(yīng)用開發(fā)之實(shí)現(xiàn)串口通信

    Python應(yīng)用開發(fā)之實(shí)現(xiàn)串口通信

    在嵌入式開發(fā)中我們經(jīng)常會(huì)用到串口,串口通信簡(jiǎn)單,使用起來方便,且適用場(chǎng)景多。本文為大家準(zhǔn)備了Python實(shí)現(xiàn)串口通信的示例代碼,需要的可以參考一下
    2022-11-11
  • pandas數(shù)據(jù)處理清洗實(shí)現(xiàn)中文地址拆分案例

    pandas數(shù)據(jù)處理清洗實(shí)現(xiàn)中文地址拆分案例

    因?yàn)楹罄m(xù)數(shù)據(jù)分析工作需要用到地理維度進(jìn)行分析,所以需要把login_place字段進(jìn)行拆分成:國家、省份、地區(qū)。感興趣的可以了解一下
    2021-06-06

最新評(píng)論

永善县| 安新县| 公安县| 威海市| 潍坊市| 大足县| 石嘴山市| 长垣县| 信宜市| 香港| 偏关县| 固安县| 贺兰县| 咸阳市| 库尔勒市| 潮安县| 五华县| 邵阳市| 河池市| 电白县| 河南省| 阜南县| 新绛县| 永寿县| 莆田市| 富裕县| 芒康县| 英超| 澄迈县| 鸡泽县| 大冶市| 徐州市| 临沧市| 青岛市| 清徐县| 大埔县| 竹北市| 固镇县| 麟游县| 宣化县| 福鼎市|