day 20

1. 類的繼承

1.1 什麼是繼承

  • 繼承是一種新建類的方式,新建的類稱爲子類,被繼承的類稱爲父類
  • 繼承的特性是:子類會遺傳父類的屬性,而且能夠派生出本身的屬性
  • 繼承是類與類之間的關係

在 python 中,一個子類能夠繼承多個父類,其餘語言只能一個子類繼承一個父類。編程

1.2 爲何要有繼承

目的:減小代碼冗餘(減小重複代碼)編程語言

1.3 如何實現繼承

  1. 先肯定誰是子類,誰是父類函數

  2. 在定義類時,子類 + (),括號內填父類的名字,實現繼承設計

    使用 __bases__ 方法,能夠獲取當前類所繼承的類3d

    class Father1:
        pass
    
    
    class Father2:
        pass
    
    
    class Son1(Father1):
        pass
    
    
    class Son2(Father1, Father2):
        pass
    
    
    print(Son1.__bases__) # 查看父類
    
    print(Son2.__bases__)

    運行結果:code

    (<class '__main__.Father1'>,)
    (<class '__main__.Father1'>, <class '__main__.Father2'>)
    
    Process finished with exit code 0

1.4 類與抽象

  • 繼承的關係
    • 對象是特徵與技能的結合體
    • 類是一系列對象相同的特徵與技能的結合體
    • 繼承是一系列類相同的特徵與技能的結合體

繼承描述的是子類與父類之間的關係,是一種什麼是什麼的關係。要找出這種關係,必須先抽象再繼承,抽象即抽取相似或者說比較像的部分。對象

抽象分紅兩個層次:blog

  1. 將奧巴馬和梅西這倆對象比較像的部分抽取成類;
  2. 將人,豬,狗這三個類比較像的部分抽取成父類。

抽象最主要的做用是劃分類別(能夠隔離關注點,下降複雜度),以下圖所示:繼承

繼承:基於抽象的結果,經過編程語言去實現它,確定是先經歷抽象這個過程,才能經過繼承的方式去表達出抽象的結構。

抽象只是分析和設計的過程當中,一個動做或者說一種技巧,經過抽象能夠獲得類,以下圖所示:

1.5 查找順序

在繼承背景下,對象屬性的查找順序:

  1. 對象查找屬性會先從對象的名稱空間中查找
  2. 若對象沒有,則會去類裏面找
  3. 若當前類是子類,而且沒有對象找的屬性,會去父類中查找

注意:對象查找屬性,若子類有,無論父類有沒有,以子類的爲準。

class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()


class Bar(Foo):
    def f1(self):
        print('Bar.f1')


# 對象查找屬性的順序:對象本身-》對象的類-》父類-》父類。。。
obj = Bar()  # self是obj自己,即找到Bar的f1()
obj.f2()

運行結果:

Foo.f2
Bar.f1

Process finished with exit code 0

2. 派生

2.1 什麼是派生

子類中新定義的屬性的這個過程叫作派生,而且須要記住子類在使用派生的屬性時始終以本身的爲準。

2.2 派生方法

2.2.1 類調用

指名道姓訪問某一個類的函數:該方式與繼承無關

# 直接經過 父類.(調用)__init__,把__init__當作普通函數使用,傳入對象與繼承的屬性.
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Son(Father):
    def __init__(self, name, age, weight, height):
        Father.__init__(self, name, age)
        self.weight = weight
        self.height = height

2.2.2 super() 方法

  • 嚴格依賴繼承屬性查找關係
  • super() 會獲得一個特殊的對象,該對象就是專門用來訪問父類中的屬性的(按照繼承的關係)
  • super().__init__ (不用爲self傳值)
  • super() 的完整用法是 super(本身的類名,self) ,在python2中須要寫完整,而python3中能夠簡寫爲 super()
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Son(Father):
    def __init__(self, name, age, weight, height):
        super().__init__(name, age)
        self.weight = weight
        self.height = height

3. 類的分類(瞭解)

在 python2 中,纔有纔會有新式類與經典類之分;在 python3 中,全部的類都是新式類。

3.1 新式類

繼承 object 的類都稱之爲新式類。

在 python3 中,若是子類沒有繼承自定義的類,都默認繼承 object 。

class Foo():
    pass


class Goo(Foo):
    pass


print(Foo.__bases__) 
print(Goo.__bases__)

運行結果:

(<class 'object'>,) # 默認繼承 object
(<class '__main__.Foo'>,)

Process finished with exit code 0

3.2 經典類

在 python2 中,凡是沒有繼承 object 的類都是經典類。

4. 菱形繼承問題

4.1 菱形繼承問題

在Java和C#中子類只能繼承一個父類,而Python中子類能夠同時繼承多個父類,如A(B,C,D)

若是繼承關係爲非菱形結構,則會按照先找B這一條分支,而後再找C這一條分支,最後找D這一條分支的順序直到找到咱們想要的屬性

若是繼承關係爲菱形結構,即子類的父類最後繼承了同一個類,那麼屬性的查找方式有兩種:

  • 經典類下:深度優先
  • 廣度優先:廣度優先

經典類:一條路走到黑,深度優先

新式類:不找多各種最後繼承的同一個類,直接去找下一個父類,廣度優先

可使用下面的代碼逐一進行驗證:

# 驗證
class A:
    def test(self):
        print('from A')

    pass


class B(A):
    def test(self):
        print('from B')

    pass


class C(A):
    def test(self):
        print('from C')

    pass


class D(B):
    def test(self):
        print('from D')

    pass


class E(C):
    def test(self):
        print('from E')

    pass


class F(D, E):
    def test(self):
        print('from F')

    pass


f1 = F()
f1.test()

結果:

# 新式類: F-D-B-E-C-A-object
# 經典類: F-D-B-A-E-C

4.2 mro() 方法

對於多繼承的類,python 提供了 mro() 方法,便捷的查看繼承的查找順序。

對於上述代碼,咱們可使用 mro() 方法:

# print(F.mro())
# 新式類下:
for i in F.mro():
    print(i)

運行結果:

<class '__main__.F'>
<class '__main__.D'>
<class '__main__.B'>
<class '__main__.E'>
<class '__main__.C'>
<class '__main__.A'>
<class 'object'>

Process finished with exit code 0
相關文章
相關標籤/搜索