1. 程式人生 > >Python_從零開始學習_(39) 繼承

Python_從零開始學習_(39) 繼承

目錄

1.  單繼承

1.1  繼承的概念,  語法和特點

1.2  方法的重寫

1.3  父類的 私有屬性 和 私有方法

2.  多繼承

2.1  多繼承的使用注意事項

2.2  新式類與舊式 (經典) 類


目標


  • 單繼承
  • 多繼承

面向物件三大特性

  1. 封裝 根據 職責 將 屬性 和 方法 封裝 到一個抽象的 類 中
  2. 繼承 實現程式碼的重用, 相同的程式碼不需要重複的編寫
  3. 多型 不同的物件呼叫相同的方法,  產生不同的執行結果,  增加程式碼的靈活度

 

1.  單繼承


1.1  繼承的概念,  語法和特點

繼承的概念:  子類 擁有 父類 的所有 方法 和 屬性

1)  繼承的語法 

class 類名(父類名):

    pass
  • 子類 繼承自 父親,  可以直接 享受 父類中已經封裝好的方法,  不需要再次開發
  • 子類 中應該根據 職責,  封裝 子類特有的 屬性和方法

2)  專業術語

  • Dog 類是 Animal 類的子類, Animal 類是 Dog 類的父類, Dog 類從 Animal 類繼承
  • Dog 類是 Animal 類的派生類, Animal 類是 Dog 類的基類, Dog 類從 Animal 類派生

3)  繼承的傳遞性

  • C 類從 B 類繼承,  B 類又從 A 類繼承
  • 那麼 C 類就具有 B 類和 A 類的所有屬性和方法

子類 擁有 父類 以及 父類的父類 中封裝的所有 屬性方法 (兒子有父親和爺爺的所有特點)

class Animal:

    def eat(self):
        print("吃")

    def drink(self):
        print("喝")

    def run(self):
        print("跑")

    def sleep(self):
        print("睡")


class Dog(Animal):

    def bark(self):
        print("叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("I can fly")


xtq = XiaoTianQuan()
xtq.run()
xtq.bark()
xtq.fly()

1.2  方法的重寫

  • 子類 擁有 父類 的所有 方法 和 屬性
  • 子類 繼承自 父類,  可以直接 享受 父類中已經封裝好的方法,  不需要再次開發

應用場景

  • 當 父類 的方法實現不能滿足子類需求時,  可以對方法進行 重新(voerwrite)

重新 父類方法有兩種情況:

  1. 覆蓋 父類的方法
  2. 對父類方法進行 擴充套件

1)  覆蓋父類的方法

  • 如果在開發中,  父類的方法實現 和 子類的方法實現, 完全不同
  • 就可以使用 覆蓋 的方式,  在子類中 重新編寫 父類的方法實現

具體的實現方式,  就相當於在 子類中 定義了一個 和父類同名的方法並且實現

重寫之後,  在執行時,  只會呼叫 子類中重寫的方法,  而不再回呼叫 父類封裝的方法

2)  對父類方法進行 擴充套件

  • 如果在開發中,  子類的方法實現 中 包含 父類的方法實現
  • 父類 原本封裝的方法實現 子類方法的一部分
  • 就可以使用 擴充套件 的方式
  1. 在子類中 重寫 父類的方法
  2. 在需要的位置使用 super( ), 父類方法 來呼叫父類方法的執行
  3. 程式碼其他的位置針對子類的需求, 編寫 子類特有的程式碼實現

關於 super

  • 在 Python 中 super 是一個 特殊的類
  • super() 就是使用 super 類創建出來的物件
  • 最常 使用的場景就是在 重寫父類方法時,  呼叫 父類中封裝的方法實現
class XiaoTianQuan(Dog):

    def fly(self):
        print("I can fly")

    def bark(self):

        # 1. 針對子類特有的需求, 編寫程式碼
        print("嗷嗚....")

        # 2. 使用super(), 呼叫原本在父類中的封裝的方法
        super().bark()

        # 3. 增加其他子類的程式碼
        print("嗷嗚嗷嗚...")

1.3  父類的 私有屬性 和 私有方法

  1. 子類物件 不能 在自己的方法內部, 直接 訪問 父類的 私有屬性私有方法
  2. 子類物件 可以通過 父類 的 公有方法 間接 訪問到 私有屬性私有方法
  • 私有屬性, 方法 是物件的隱私,  不對外公開,  外界 以及 子類 都不能直接訪問
  • 私有屬性, 方法 通常用於做一些內部的事情
  • B 的物件不能直接訪問 __num2 屬性
  • B 的物件不能再 demo 方法內訪問 __num2 屬性
  • B 的物件可以在 demo 方法內, 呼叫父類的 test 方法
  • 父類的 test 方法內部,  能夠訪問 __num2 屬性和 __test 方法
class A:

    def __init__(self):

        self.num1 = 100
        self.__num2 = 200

    def __test(self):
        print("私有方法 %d %d" % (self.num1, self.__num2))

    def test(self):
        print("父類的公有方法 %d" % self.__num2)

        self.__test()


class B(A):

    def demo(self):

        # 1. 在子類的物件方法中, 不能訪問父類的私有屬性
        # print("訪問父類的私有屬性 %d" % self.__num2)

        # 2. 在子類的物件方法中, 不能訪問父類的私有方法
        # self.__test()

        # 3. 訪問父類的公有屬性
        print("子類方法 %d" % self.num1)

        # 4. 訪問父類的公有方法
        self.test()


b = B()
print(b)

b.demo()
# print(b.num1)
# b.test()

# 在外界不能直接訪問物件的私有屬性和私有方法
# print(b.__num2)
# print(b.__test)

 

2.  多繼承


概念

  • 子類 可以擁有 多個父類,  並且具有 所有父類 屬性 方法
  • 例如: 孩子 會繼承自己 父親 母親 特性

語法

class 子類名(父類名1, 父類名2...):
    pass

2.1  多繼承的使用注意事項

問題的提出

  • 如果 不同的父類 中存在 同名的方法,  子類物件 在呼叫方法時,  會呼叫 哪一個父類中的方法呢?

提示 : 開發時,  應該儘量避免這種容易產生混淆的情況!  ---- 如果 父類之間 存在 同名的屬性或者方法,  應該 儘量避免 使用多繼承

 例如 :

class A:

    def test(self):
        print("父類A")


class B:

    def test(self):
        print("父類B")


class C(A, B):
    """多繼承可以讓子類物件, 同時具有多個父類的屬性和方法"""
    pass


# 建立子類
c = C()
c.test()

Python 中的 MRO ---- 方法搜尋順序 (科普)

  • Python 中針對 類 提供了一個 內建屬性 __mro__ 可以檢視 方法 搜尋順序
  • MRO 是 method resolution order , 主要用於 在多繼承時判斷 方法, 屬性, 的呼叫 路徑
print(C.__mro__)

輸出結果 

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
  • 在搜尋方法時,  是按照 __mro__的輸出結果 從左至右 的順序查詢的
  • 如果在當前類中 找到方法,  就直接執行,  不再搜尋
  • 如果 沒有找到, 就查詢下一個類 中是否有對應的方法,  如果找到,  就直接執行,  不再搜尋
  • 如果找到最後一個類,  還沒找到方法,  程式報錯

2.2  新式類與舊式 (經典) 類

object 是 Python 為所有物件提供的 基類,  提供有一些內建的屬性和方法,  可以使用 dir 函式檢視

  • 新式類 :  以 object 為基類的類,  推薦使用
  • 經典類 :  不以 object 為基類的類,  不推薦使用
  • 在 Python 3.x 中定義類時,  如果沒有指定父類,  會 預設使用 object 作為該類的 基類  ----  Python 3.x 中定義的類都是 新式類
  • 在 Python 2.x 中定義類時,  如果沒有指定父類,  則不會以 object 作為 基類

新式類 和 經典類 在多繼承時 ---- 會影響到方法的搜尋順序

為了保證保證編寫的程式碼能夠同時在 Python 2.x 和 Python 3.x 執行!

今後在定義類時,  如果沒有父類,  建議統一繼承自 object

class 類名(object):
    pass