欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳析Python面向對象中的繼承

 更新時間:2022年03月07日 11:11:37   作者:搬磚,贊路費  
這篇文章主要詳析Python面向對象中的繼承,類繼承作為python的三大特性之一,在我們學習python的時候是必不可少的。使用類繼承,能夠大大減少重復代碼的編寫,下文詳細內容需要的小伙伴可以參考一下

一 單繼承

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

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

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

單繼承的話一般類A是沒有繼承其他派生類的,只繼承了基類。因為在python新式類中,一個類會默認去繼承基類object的,基類object是頂級類。

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())

如上:我們定義了一個父類Father,一個子類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類確實繼承了Father類,并且繼承基類object。

3. 繼承中的屬性和方法

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

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):
? ? ? ? #調用父類屬性和方法
? ? ? ? print(self.age1, self.name1)
? ? ? ? self.father_method()

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

結果如下:

>>>
father_age father_name
我是父親

當子類中的屬性名方法名和父類中的屬性名方法名同名時,在該子類中會覆蓋父類的屬性名和方法名(重寫)。

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):
? ? ? ? #和父類方法同名,將以子類方法為準
? ? ? ? print("與父類方法同名,但是我是子類")

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


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

輸出如下:

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

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

上面寫的子類和父類都是不需要傳參數(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ù)時,無需進行__init__ 初始化,直接調用父類的對象屬性即可。因為子類Son是繼承自父類Father的,所以在調用時會首先去調父類的__init__ 進行初始化

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

當子類有新增參數(shù)時,該怎么初始化呢?先來看看這個對不對

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新增了一個height參數(shù),然后用__init__ 進行初始化。但是從輸出結果可以看出,height參數(shù)是正常打印的,打印name和age參數(shù)時就報錯:子類Son沒有屬性’name’,因為這個時候就不會去調用父類的__init__ 進行初始化,而是直接調用子類中的__init__ 進行初始化,這時,子類初始化就會覆蓋掉父類的__init__ 初始化,從而報錯。

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

#方法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

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

現(xiàn)在來看看另外一個初始化方法super()初始化,不過使用super()的時候要注意python的版本,因為python2和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()

結果:

>>>
175
李四 24

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

二 多層繼承

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

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

繼承關系:

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

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

這里就涉及到super的繼承機制,即super會根據(jù)MRO機制,從左到右依次調用父類的屬性和方法, 當父類中有同屬性名,同方法名時,以靠左的那個父類為準。

下面我們把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):#這里變動,變換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 mother
leave mother
leave son
這是mather
[<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]

繼承關系:

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

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

三 多重繼承

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

如下:

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

先來看看如下的一個菱形繼承:

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()

輸出結果:

>>>
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__ () 來進行子類初始化的,但是從結果來看,類A的初始化方法是被執(zhí)行了兩次的,一次是類B的調用,一次是類C的調用。也可以看出子類D的初始化 __ init __ 調用了B.__ init __() 和C. __init __() ?,F(xiàn)在D類繼承的父類只有B和C,但是當代碼比較復雜,繼承的類比較多時,就得的一個一個寫,如果類B和類C也是繼承自多個類,那它們的初始化方法也得重新寫,這樣就比較繁瑣,也容易出錯。

下面來使用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())

輸出結果:

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'>]

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

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

到此這篇關于詳析Python面向對象中的繼承的文章就介紹到這了,更多相關Python面向對象繼承內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • python list元素為tuple時的排序方法

    python list元素為tuple時的排序方法

    下面小編就為大家分享一篇python list元素為tuple時的排序方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • Pandas數(shù)據(jù)分組統(tǒng)計的實現(xiàn)示例

    Pandas數(shù)據(jù)分組統(tǒng)計的實現(xiàn)示例

    對數(shù)據(jù)進行分組統(tǒng)計,主要適用DataFrame對象的groupby()函數(shù),本文就來詳細的介紹下Pandas數(shù)據(jù)分組統(tǒng)計的實現(xiàn),具有一定的參考價值,感興趣的可以了解下
    2023-11-11
  • 使用Python腳本和ADB命令實現(xiàn)卸載App

    使用Python腳本和ADB命令實現(xiàn)卸載App

    這篇文章主要介紹了使用Python腳本和ADB命令實現(xiàn)卸載App的實現(xiàn)方法,文中給出了完整的示例代碼,相信對大家具有一定的參考價值,有需要的朋友們下面來一起看看吧。
    2017-02-02
  • 使用Python的toolz庫開始函數(shù)式編程的方法

    使用Python的toolz庫開始函數(shù)式編程的方法

    這篇文章主要介紹了使用Python的toolz庫開始函數(shù)式編程的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • python的staticmethod與classmethod實現(xiàn)實例代碼

    python的staticmethod與classmethod實現(xiàn)實例代碼

    這篇文章主要介紹了python的staticmethod與classmethod實現(xiàn)實例代碼,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • python中abs&map&reduce簡介

    python中abs&map&reduce簡介

    map與reduce是兩個十分常用的Python內置函數(shù),它們與Hadoop中的MapReduce在某些方面有一定的相似之處。
    2018-02-02
  • python+Splinter實現(xiàn)12306搶票功能

    python+Splinter實現(xiàn)12306搶票功能

    這篇文章主要為大家詳細介紹了python+Splinter實現(xiàn)12306搶票功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • centos 下面安裝python2.7 +pip +mysqld

    centos 下面安裝python2.7 +pip +mysqld

    這篇文章主要介紹了centos 下面安裝python2.7 +pip +mysqld,需要的朋友可以參考下
    2014-11-11
  • Python標準庫uuid模塊(生成唯一標識)詳解

    Python標準庫uuid模塊(生成唯一標識)詳解

    uuid通過Python標準庫的uuid模塊生成通用唯一ID(或“UUID”)的一種快速簡便的方法,下面這篇文章主要給大家介紹了關于Python標準庫uuid模塊(生成唯一標識)?的相關資料,需要的朋友可以參考下
    2022-05-05
  • python使用技巧-查找文件?

    python使用技巧-查找文件?

    這篇文章主要分享的是python使用技巧查找文件,下面我們就來介紹針對python查找文件的相關內容,需要的小伙伴可以參考一下
    2022-02-02

最新評論