Python面向對象中的繼承、多態和封裝

来源:https://www.cnblogs.com/wangyueping/archive/2019/06/28/11094635.html
-Advertisement-
Play Games

Python面向對象中的繼承、多態和封裝 一、面向對象的三大特性 1. 封裝:把很多數據封裝到⼀個對象中,把固定功能的代碼封裝到⼀個代碼塊, 函數,對象, 打包成模塊。 這都屬於封裝思想。 2. 繼承:⼦類可以⾃動擁有⽗類中除了私有屬性外的其他所有內容。 說⽩了, ⼉⼦可以隨便⽤爹的東⻄。 3. 多 ...


Python面向對象中的繼承、多態和封裝

一、面向對象的三大特性

  1. 封裝:把很多數據封裝到⼀個對象中,把固定功能的代碼封裝到⼀個代碼塊, 函數,對象, 打包成模塊。 這都屬於封裝思想。
  2. 繼承:⼦類可以⾃動擁有⽗類中除了私有屬性外的其他所有內容。 說⽩了, ⼉⼦可以隨便⽤爹的東⻄。
  3. 多態: 同⼀個對象, 多種形態。在Python中處處是多態,因為在Python中一個變數可以是多種形態。

二、封裝

封裝,顧名思義,就是將某些東西給封裝起來,以後想要使用的時候再去調用。

所以,在使用面向對象的封裝特性時需要:① 將內容封裝到某處 ② 調用時從某處取出來

封裝分為兩部分:

  1. 廣義上的封裝:實例化一個對象,給對象空間封裝一些屬性。
  2. 狹義上的封裝:私有制。私有成員:私有靜態屬性,私有方法,私有對象屬性。

我們先看廣義上的封裝:

  1. 將內容封裝到某處

    class MyClass:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    # 在實例化對象時,會自動執行__init__方法,將對象空間傳遞給self這個位置參數
    obj = MyClass("oldniu", 20)
    # 將"oldniu" 和 20 分別封裝到obj(self)的name和age屬性中
  2. 從某處調用封裝的內容

    調用被封裝的內容時,有兩種方式:① 通過對象直接調用 ② 通過self間接調用

    1. 通過對象直接調用

      class MyClass:
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
      
      obj = MyClass("oldniu", 20)
      print(obj.name)     # 通過obj對象直接調用裡面的name屬性
      print(obj.age)      # 通過obj對象直接調用裡面的age屬性
    2. 通過self間接調用

      class MyClass:
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          def func(self):
              print(self.name)    # 使用self間接調用obj對象中的name屬性
              print(self.age)     # 使用self間接調用obj對象中的age屬性
      
      
      obj = MyClass("oldniu", 20)
      obj.func()  # 對象執行方法時Python會預設將obj傳給參數self

    綜上所述,對於面向對象廣義上的封裝來說,其實就是使用初始化方法將內容封裝到 對象 中,然後通過對象直接或者self間接獲取被封裝的內容。

    我們再看狹義上的封裝

    1. 私有靜態屬性

      class MyClass:
          __gender = "男"  # 私有靜態屬性
      
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          def get_gender(self):
              return self.__gender    # 在類的內部可以訪問私有靜態屬性
      
      # print(MyClass.__gender)     # 類名不能直接訪問私有靜態屬性
      
      obj = MyClass("oldniu", 20)
      # print(obj.__gneder)         # 對象不能訪問私有靜態屬性
      
      print(obj.get_gender())     # 男
      

      對於私有靜態欄位來說,只能在本類中內部訪問,類的外部,子類均不可訪問。

      tips:其實在類的外部可以通過使用_MyClass__gender訪問私有靜態屬性,但是一般我們不會去使用。

    2. 私有方法

      class MyClass:
      
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          def __func(self):
              print("666666")
      
          def func(self):
              self.__func() 類內部訪問靜態方法
      
      
      obj = MyClass("dogfa", 20)
      obj.func()
      # 私有方法和私有靜態欄位一樣,只能在本類中內部訪問,類的外部和子類均不課訪問。

    三、繼承

    什麼是繼承?⼦類可以⾃動擁有⽗類中除了私有屬性外的其他所有內容就是繼承。

    1. 繼承的優點
      1. 提高代碼的復用性
      2. 提高代碼的維護性
      3. 使類與類之間發生關聯
    2. 繼承的分類
      1. 單繼承
      2. 多繼承

    我們先來看單繼承

    1. 類名,對象執行父類方法

      # 定義一個Animal父類
      class Animal:
          type_name = "動物類"
      
          def __init__(self, name):
              self.name = name
      
          def eat(self):
              print("吃吃吃...")
      
      # 繼承於Animal類
      class Dog(Animal):
          pass
      
      # 類名調用父類的屬性和方法
      print(Dog.type_name)
      Dog.eat(111)
      
      # 對象調用父類的屬性和方法
      dog = Dog("二哈")   # 調用父類的__init__方法實例化對象
      print(dog.name)
      print(dog.type_name)
      dog.eat()
      print(dog.__dict__)
    2. 執行順序

      1. 實例化對象時必須執行__init__方法,類中沒有,從父類找,父類沒有,從object類中找。
      2. 先要執行自己類中的eat方法,自己類沒有才能執行父類中的方法。
    3. 同時執行類及父類方法

      方法一:

      如果想執行父類的func方法,這個方法並且子類中夜用,那麼就在子類的方法中寫上:

      父類.func(對象,其他參數)

      class Animal:
          type_name = "動物類"
      
          def __init__(self, name, age, gender):
              self.name = name
              self.age = age
              self.gender = gender
      
          def eat(self):
              print("吃吃吃...")
      
      class Bird(Animal):
          def __init__(self, name, age, gender, wing):        
              Animal.__init__(self, name, age, gender)    # 執行了父類的__init__方法進行初始化
              self.wing = wing    # 給對象封裝wing屬性
      
      obj = Bird("鸚鵡", 3, "雌", "翅膀")
      print(obj.__dict__)
      # {'name': '鸚鵡', 'age': 3, 'gender': '雌', 'wing': '翅膀'}

      方法二:

      利用super,super().func(參數)

      class Animal:
          type_name = "動物類"
      
          def __init__(self, name, age, gender):
              self.name = name
              self.age = age
              self.gender = gender
      
          def eat(self):
              print("吃吃吃...")
      
      class Bird(Animal):
          def __init__(self, name, age, gender, wing):
              super().__init__(name, age, gender)    # 使用super會自動將self傳給父類
              self.wing = wing    # 給對象封裝wing屬性
      
      obj = Bird("鸚鵡", 3, "雌", "翅膀")
      print(obj.__dict__)
      # {'name': '鸚鵡', 'age': 3, 'gender': '雌', 'wing': '翅膀'}

    再來看看多繼承

    在多繼承中要補充一點,在這裡要註意類的種類。類可以分為經典類新式類

    新式類:繼承object類的類稱為新式類。在Python3中預設都是繼承object類,所以預設所有類都是新式類。

    經典類:不繼承object類的類稱為經典類。在Python2中預設使用經典類,當然也可以自己手動繼承object類來達到變成經典類的目的。

    1. 經典類的多繼承

      在Python的繼承體系中, 我們可以把類與類繼承關係化成⼀個樹形結構的圖。

      class A:
          pass
      class B(A):
          pass
      class C(A):
          pass
      class D(B, C):
          pass
      class E:
          pass
      class F(D, E):
          pass
      class G(F, D):
          pass
      class H:
          pass
      class Foo(H, G):
          pass

      對付這種mro畫圖就可以:

      繼承關係圖已經有了,那如何進⾏查找呢? 記住⼀個原則, 在經典類中採⽤的是深度優先遍歷⽅案。 什麼是深度優先,就是⼀條路走到頭, 然後再回來, 繼續找下⼀個。

      類的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C

    2. 新式類的繼承

      1. mro序列

        MRO是一個有序列表L,在類被創建時就計算出來。
        通用計算公式為:

        mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
        (其中Child繼承自Base1, Base2)

        如果繼承至一個基類:class B(A)
        這時B的mro序列為

        mro( B ) = mro( B(A) )
        = [B] + merge( mro(A) + [A] )
        = [B] + merge( [A] + [A] )
        = [B,A]

        如果繼承至多個基類:class B(A1, A2, A3 …)
        這時B的mro序列

        mro(B) = mro( B(A1, A2, A3 …) )
        = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
        = ...

        計算結果為列表,列表中至少有一個元素即類自己,如上述示例[A1,A2,A3]。merge操作是C3演算法的核心。

      2. 表頭和表位

        表頭:
          列表的第一個元素

        表尾:
          列表中表頭以外的元素集合(可以為空)

        示例
          列表:[A, B, C]
          表頭是A,表尾是B和C

      3. 列表之間的+操作

        +操作:

        [A] + [B] = [A, B]
        (以下的計算中預設省略)
        ---------------------

        merge操作示例:

        如計算merge( [E,O], [C,E,F,O], [C] )
        有三個列表 :  ①      ②          ③
        
        1 merge不為空,取出第一個列表列表①的表頭E,進行判斷                              
           各個列表的表尾分別是[O], [E,F,O],E在這些表尾的集合中,因而跳過當前當前列表
        2 取出列表②的表頭C,進行判斷
           C不在各個列表的集合中,因而將C拿出到merge外,並從所有表頭刪除
           merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
        3 進行下一次新的merge操作 ......
        --------------------- 

        計算mro(A)方式:

        mro(A) = mro( A(B,C) )
        
        原式= [A] + merge( mro(B),mro(C),[B,C] )
        
          mro(B) = mro( B(D,E) )
                 = [B] + merge( mro(D), mro(E), [D,E] )  # 多繼承
                 = [B] + merge( [D,O] , [E,O] , [D,E] )  # 單繼承mro(D(O))=[D,O]
                 = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出並刪除D
                 = [B,D,E] + merge([O] ,  [O])
                 = [B,D,E,O]
        
          mro(C) = mro( C(E,F) )
                 = [C] + merge( mro(E), mro(F), [E,F] )
                 = [C] + merge( [E,O] , [F,O] , [E,F] )
                 = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳過O,拿出並刪除
                 = [C,E,F] + merge([O] ,  [O])
                 = [C,E,F,O]
        
        原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
            = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])
            = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳過E
            = [A,B,D,C] + merge([E,O],  [E,F,O])
            = [A,B,D,C,E] + merge([O],    [F,O])  # 跳過O
            = [A,B,D,C,E,F] + merge([O],    [O])
            = [A,B,D,C,E,F,O]
        --------------------- 

三、多態

多態:同一個對象,多種形態。

由於Python是弱類型語言, 在定義變數和傳參的時候可以是任意形態的值,所以Python預設支持多態。

鴨子類型:你看起來像鴨子,那就是鴨子。

對相同的功能設定了相同的名字,這樣方便開發,這兩個方法就可以互成為鴨子類型。比如list、tuple、str都有index()方法,這就是互稱為鴨子類型。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、簡介 SOA(Service Oriented Architecture)“面向服務的架構”:他是一種設計方法,其中包含多個服務, 服務之間通過相互依賴最終提供一系列的功能。一個服務 通常以獨立的形式存在與操作系統進程中。各個服務之間 通過網路調用。 2、和微服務對比 微服務架構其實和 SOA ...
  • MTDDL 美團分散式數據訪問中間件(轉) "原文地址:MTDDL——美團點評分散式數據訪問層中間件" 因原文文字和圖顯示有問題,故整理於此,僅供參考。 業界方案 | 組件 | 簡介 | | : : | : | | Atlas | Qihoo 360開發維護的一個基於MySQL協議的數據中間層項目。 ...
  • 適配器主要用於介面的轉換或者將介面不相容的類對象組合在一起形成對外統一介面,是一種結構性模式,其本質是是一個中間件,適用於類及其對象。本文希望通過簡單的介紹和分析,能讓讀者對適配器模式有一個簡單直觀的認識和感知。 1.目的 對現有的類的介面進行轉換以符合新的需求。 2.動機 通過轉換或者組合,間接復 ...
  • CDN加速靜態文件訪問 全局調度 緩存技術 內容分發 帶寬優化 CDN是Content Delivery Network的縮寫,意思是內容分髮網絡。CDN的作用是把用戶需要的內容分發到離用戶近的地方,這樣可以使用戶 能夠就近獲取所需內容。 整個CDN系統(如圖1-1所示)分為CDN源站和CDN節點, ...
  • 3.3 如何從ubuntu或PC傳遞文件到板子,ubuntu如何上網? 答:以下將分別介紹如何在ubuntu和windows下如何傳遞文件。 ubuntu如何配置上網?ubuntu 上網:打開Oracle VM VirtualBox(虛擬機軟體,筆者以此軟體為例,也可用其他虛擬機軟體)管理器中的設置 ...
  • 編者註:前段時間筆者在團隊內部分享了sentinel原理設計與實現,主要講解了sentinel基礎概念和工作原理,工作原理部分大家聽了基本都瞭解了,但是對於sentinel的幾個概念及其之間的關係還有挺多同學有點模糊的,趁著這幾天比較空,針對sentinel的幾個核心概念,做了一些總結,希望能幫助一 ...
  • [TOC] 一、概述 做客戶端開發已經有好幾個年頭了,今天看到同事發了一篇關於富途牛牛的文章,核心思想就是想說,新版本的富途支持多進程架構了,效率大大提升啦,可以更好的適應多核CPU,提高軟體運行效率。 聽到這個消息,我不僅感嘆,我靠,真的好牛逼。 但是心裡又在默默的想,這個東西到底有什麼好處,多進 ...
  • 知識點講解:python系列——文件操作 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...