Python物件導向編程-02

來源:互聯網
上載者:User

標籤:lis   設定   ref   開放   建構函式   ima   方便   父類   false   

本知識點參考廖雪峰的Python課程 [https://www.liaoxuefeng.com]感謝北京圖靈知非的免費課程 [http://www.tulingxueyuan.com/]

2018/6/26 星期二 11:15:57

繼承和多態
  • 繼承就是一個類可以獲得另外一個類中的成員屬性和成員方法
    • 作用: 減少代碼,增加代碼的複用功能, 同時可以設定類與類直接的關係
  • 繼承與被繼承的概念:
    • 被繼承的類叫父類,也叫基類,也叫超類
    • 用於繼承的類,叫子類,也叫衍生類別
    • 繼承與被繼承一定存在一個 is-a 關係
  • 繼承的文法:

        class Animal(object):        def run(self):        print("Animal is runnung...")    # Animal 繼承於object,第一個類都繼承於object,不管你寫不寫`object`    class Dog(Animal):        pass    # Dog繼承於Animal    class Cat(Animal):        pass    # Cat繼承於Animal
  • 對於Dog來說,Animal就是它的父類,對於Animal來說,Dog就是它的子類
  • 繼承的好處就在於子類獲得了父類的全部功能。Dog也有了AnimalRun() 方法

    >>> dog = Dog()# 子類一旦繼承父類,則可以使用父類中除私人成員外的所有內容>>> dog.runAnimal is runnung...
  • 我們對上面代碼再次進行改進,給DogCat添加一些方法

        class Dog(Animal):        def run(self):            print(‘Dog is running...‘)    class Cat(Animal):        def run(self):            print(‘Cat is running...‘)
  • 運行:

        >>> dog = Dog()    >>> cat = Cat()    >>> dog.run()    >>> cat.run()    Dog is running...    Cat is running...
  • 我們可以看到這裡,子類和父類都存在run方法時,子類的run()覆蓋了父類的run().在代碼啟動並執行時候總會調用子類的run().這樣我們就獲得了繼承的另外一個好處,多態。

    多態
  • 要理解什麼是多態,我們首先要對資料類型再作一點說明。當我們定義一個class的時候,我們實際上就定義了一種資料類型。我們定義的資料類型和Python內建的資料類型,比如str、list、dict沒什麼兩樣:

        a = list() # a是list類型    b = Animal() # b是Animal類型    c = Dog() # c是Dog類型
  • 判斷一個變數是否是某個類型可以用isinstance()判斷:

         >>> isinstance(a, list)     True     >>> isinstance(b, Animal)     True     >>> isinstance(c, Dog)     True
  • 看來abc都對於著list、Animal、Dog這三種類型
  • 但是:

        >>> isinstance(c,Animal)    True
  • 看來c不僅僅是Dog,c還是Animal
    不過仔細想想,這是有道理的,因為Dog是從Animal繼承下來的,當我們建立了一個Dog的執行個體c時,我們認為c的資料類型是Dog沒錯,但c同時也是Animal也沒錯,Dog本來就是Animal的一種!
  • 所以,在繼承關係中,如果一個執行個體的資料類型是某個子類,那它的資料類型也可以被看做是父類。但是,反過來就不行:

        >>> b = Animal()    >>> isinstance(b, Dog)    False
  • 要理解多態的好處,我們編寫一個函數

        def run_twice(animal):        animal.run()        animal.run()
  • 當我們傳入Animal的執行個體時,run_twice()就列印出:

        >>> def run_twice(Animal()):    Animal is running..    Animal is running..
  • 當我們傳入Dog的執行個體時,run_twice()就列印出:

        >>> def run_twice(Dog()):    Dog is running..    Dog is running..
  • 當我們傳入Cat的執行個體時,run_twice()就列印出:

        >>> def run_twice(Cat()):    Cat is running..    Cat is running..
  • 如果我們再定義一個Tortoise類型,也從Animal派生:

        class Tortoise(Animal):        def run(self):            print(‘Tortoise is running slowly...‘)  
  • 當我們調用run_twice()時,傳入Tortoise的執行個體:

        >>> run_twice(Tortoise())    Tortoise is running slowly...    Tortoise is running slowly...
  • 對於一個變數,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調用run()方法,而具體調用的run()方法是作用在Animal、Dog、Cat還是Tortoise對象上,由運行時該對象的確切類型決定,這就是多態真正的威力:調用方只管調用,不管細節,而當我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的代碼是如何調用的。這就是著名的“開閉”原則:

    • 對擴充開放:允許新增Animal子類;
    • 對修改封閉:不需要修改依賴Animal類型的run_twice()等函數。

添加:

  • super()
  • 子類如果想擴充父類的方法,可以在定義新方法的同時訪問父類成員來進行代碼重用,可以使用 [父類名.父類成員] 的格式來調用父類成員,也可以使用super().父類成員的格式來調用。

        class Animal(object):        def run(self):        print("Animal is runnung...")    class Dog(Animal):        def run(self):            print(‘Dog is running...‘)    class Cat(Animal):        def run(self):            super().run()            print(‘Cat is running...‘)
  • 繼承變數函數的尋找順序問題
    • 優先尋找自己的變數
    • 沒有則尋找父類
    • 建構函式如果本類中沒有定義,則自動尋找調用父類建構函式
    • 如果本類有定義,則不在繼續向上尋找
  • 建構函式
    • 是一類特殊的函數,在類進行執行個體化之前進行調用
    • 如果定義了建構函式,則執行個體化時使用建構函式,不尋找父類建構函式
    • 如果沒定義,則自動尋找父類建構函式
    • 如果子類沒定義,父類的建構函式帶參數,則構造對象時的參數應該按父類參數構造
多繼承於重繼承
  • 繼承物件導向編程的一個重要方式,通過繼承,子類就可以擴充父類的功能
  • 如果我們把我們能想到的動物進行分類
    • Dog - 狗狗;
    • Bat - 蝙蝠;
    • Parrot - 鸚鵡;
    • Ostrich - 鴕鳥
  • 我們能飛的,能跑的,能遊的,哺乳動物等分類,就太麻煩了,類的數量會指數級增長
  • 我們正確的做法是採用多重繼承,首先主要層次任然安裝哺乳動物,和鳥類分:

    class Animal(object):    pass# 大類:class Mammal(Animal):    passclass Bird(Animal):    pass# 各種動物:class Dog(Mammal):    passclass Bat(Mammal):    passclass Parrot(Bird):    passclass Ostrich(Bird):    pass
  • 然後,我們在給動物加上Runnable和Flyable的功能,只需要先定義好Runnable和Flyable的類:

    class Runnable(object):    def run(self):        print(‘Running...‘)class Flyable(object):    def fly(self):        print(‘Flying...‘)

    -對於需要Runnable功能的動物,就多繼承一個Runnable,例如Dog:

    class Dog(Mammal, Runnable):    pass
  • 對於需要Flyable功能的動物,就多繼承一個Flyable,例如Bat:

    class Bat(Mammal, Flyable):    pass

    通過多重繼承,一個子類就可以同時獲得多個父類的所有功能。

  • Mixin
  • Mixin設計模式
    • 主要採用多繼承方式對類的功能進行擴充
    • Mixin概念
    • MRO and Mixin
    • Mixin模式
    • Mixin MRO
    • MRO
  • 我們使用多繼承文法來實現Minxin
  • 使用Mixin實現多繼承的時候非常小心
    • 首先他必須表示某一單一功能,而不是某個物品
    • 職責必須單一,如果由多個功能,則寫多個Mixin
    • Mixin不能依賴於子類的實現
    • 子類及時沒有繼承這個Mixin類, 也能照樣工作,只是缺少了某個功能
  • 優點
    • 使用Mixin可以在不對類進行任何修改的情況下,擴充功能
    • 可以方便的組織和維護不同功能組件的劃分
    • 可以根據需要任意調整功能類的組合
    • 可以避免建立很多新的類,導致類的繼承混亂

Python物件導向編程-02

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.