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

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

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

一 單繼承

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

1. 繼承的基本語(yǔ)法格式如下

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

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

2. 查看類(lèi)繼承情況

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

class Son(Father):
? ? #這是子類(lèi)
? ? 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è)父類(lèi)Father,一個(gè)子類(lèi)Son,并且子類(lèi)Son繼承父類(lèi)Father,它們都有自己的屬性和方法。我們可以通過(guò)打印B.__ class__.__mro __ 或者Son.mro()來(lái)查看Son類(lèi)的繼承情況,如下:

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

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

3. 繼承中的屬性和方法

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

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

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

? ? def fun1(self):
? ? ? ? #調(diào)用父類(lèi)屬性和方法
? ? ? ? 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)子類(lèi)中的屬性名方法名和父類(lèi)中的屬性名方法名同名時(shí),在該子類(lèi)中會(huì)覆蓋父類(lèi)的屬性名和方法名(重寫(xiě))。

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

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

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

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


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

輸出如下:

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

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

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

子類(lèi)無(wú)新增參數(shù):

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

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

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

輸出:

>>>
張三 23

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

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

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

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

class Son(Father):
? ? #子類(lèi)
? ? 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

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

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

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

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

class Son(Father):
? ? #子類(lèi)
? ? 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)用父類(lèi)初始化后,結(jié)果就正常輸出。這是在子類(lèi)__init__初始化的時(shí)候,調(diào)用了Father.__ init __(self, name, age)對(duì)父類(lèi)對(duì)象屬性進(jìn)行了初始化。

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

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


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

class Son(Father):
? ? #子類(lèi)
? ? 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) 來(lái)對(duì)父類(lèi)對(duì)象屬性進(jìn)行初始化。不過(guò)這是要區(qū)分python版本的,在python3中使用super(Son, self).__ init__(name, age)或者super().__ init__(name, age)都是可以的,但是在python2的版本中,要使用super(Son, self).__ init__(name, age)來(lái)進(jìn)行初始化,而且父類(lèi)必須繼承object,否則就會(huì)報(bào)錯(cuò)。

二 多層繼承

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

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

這里就涉及到super的繼承機(jī)制,即super會(huì)根據(jù)MRO機(jī)制,從左到右依次調(diào)用父類(lèi)的屬性和方法, 當(dāng)父類(lèi)中有同屬性名,同方法名時(shí),以靠左的那個(gè)父類(lèi)為準(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)用的就是類(lèi)Mather的初始化方法和fun方法。所以在多層繼承時(shí),一定要注意父類(lèi)的位置順序。

三 多重繼承

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

如下:

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

先來(lái)看看如下的一個(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'>]

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

下面來(lái)使用super初始化父類(lèi)看看:

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

所以在類(lèi)的多重繼承中,一般建議使用super來(lái)初始化父類(lèi)對(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)行,或者程序員最喜歡的編寫(xiě).py文件,在文件中編寫(xiě)python代碼,然后運(yùn)行。如果想寫(xiě)一篇Python的文章,里面有代碼,還希望代碼在當(dāng)前頁(yè)面運(yùn)行,那就是使用我們今天要介紹的Jupyter Notebook。
    2021-06-06
  • 深入學(xué)習(xí)Python中的裝飾器使用

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

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

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

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

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

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

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

    今天小編就為大家分享一篇關(guān)于Python字典的核心底層原理講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    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ì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Python應(yīng)用開(kāi)發(fā)之實(shí)現(xiàn)串口通信

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

    在嵌入式開(kāi)發(fā)中我們經(jīng)常會(huì)用到串口,串口通信簡(jiǎn)單,使用起來(lái)方便,且適用場(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)行拆分成:國(guó)家、省份、地區(qū)。感興趣的可以了解一下
    2021-06-06

最新評(píng)論

班戈县| 开封县| 凤翔县| 罗山县| 东乌珠穆沁旗| 武义县| 武鸣县| 同江市| 定兴县| 和田市| 鹰潭市| 商洛市| 咸丰县| 蓝田县| 金坛市| 建水县| 东乌珠穆沁旗| 乐至县| 阿坝| 永春县| 镇坪县| 巨野县| 阳原县| 晋江市| 台南市| 手机| 开化县| 德令哈市| 车致| 朔州市| 山东| 洪湖市| 鄂尔多斯市| 焉耆| 临洮县| 潞西市| 哈巴河县| 嘉黎县| 龙州县| 休宁县| 台中县|