python基礎---理解面向對象

一、面向過程 VS 面向對象

1、面向過程

面向過程的程序設計的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就好比精心設計好一條流水線,考慮周全什麼時候處理什麼東西。

  • 優點:極大的降低了寫程序的複雜度,只需要順着要執行的步驟,堆疊代碼即可。
  • 缺點:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。
  • 應用場景:一旦完成基本很少改變的場景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

2、面向對象

面向對象的程序設計的核心是對象(上帝式思維),要理解對象爲何物,必須把自己當成上帝,上帝眼裏世間存在的萬物皆爲對象,不存在的也可以創造出來。

  • 優點:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物參數的特徵和技能修改都很容易。
  • 缺點:可控性差,無法向面向過程的程序設計流水線式的可以很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即便是上帝也無法預測最終結果。
  • 應用場景:需求經常變化的軟件,一般需求的變化都集中在用戶層,互聯網應用,企業內部軟件,遊戲等都是面向對象的程序設計大顯身手的好地方。

二、名詞理解

類:具有相同特徵的一類事物,其主要作用是屬性的引用和實例化
對象/實例:具體的某一個事物,其作用是屬性的引用
實例化:類名加括號就是實例化,會自動觸發init函數的運行(運行前先運行new()開闢一塊內存空間),可以用它來爲每個實例定製自己的特徵

三、類的屬性

創建一個類就會創建一個類的名稱空間,用來存儲類中定義的所有名字,這些名字稱爲類的屬性,類有兩種屬性:靜態屬性和動態屬性

  • 靜態屬性就是直接在類中定義的變量
  • 動態屬性就是定義在類中的方法

創建一個對象/實例就會創建一個對象/實例的名稱空間,存放對象/實例的名字,稱爲對象/實例的屬性
一:我們定義的類的屬性到底存到哪裏了?有兩種方式查看

dir(類名):查出的是一個名字列表
類名.dict:查出的是一個字典,key爲屬性名,value爲屬性值

二:特殊的類屬性

類名.name# 類的名字(字符串)
類名.doc# 類的文檔字符串
類名.base# 類的第一個父類(在講繼承時會講)
類名.bases# 類所有父類構成的元組(在講繼承時會講)
類名.dict# 類的字典屬性
類名.module# 類定義所在的模塊
類名.class# 實例對應的類(僅新式類中)

四、面向對象的組合用法

  軟件重用的重要方式除了繼承之外還有另外一種方式,即:組合。組合指的是,在一個類中以另外一個類的對象作爲數據屬性,稱爲類的組合
  當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好

五、面向對象的三大特性

1、繼承順序(鑽石繼承)
這裏寫圖片描述

2、繼承原理
  python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,例如: F.mro() #等同於F.mro[, , , , , , ]
  繼承順序實際上就是合併所有父類的MRO列表並遵循如下三條準則:

  1. 子類會先於父類被檢查
  2. 多個父類會根據它們在列表中的順序被檢查
  3. 如果對下一個類存在兩個合法的選擇,選擇第一個父類

3、抽象類
接口類

繼承有兩種用途:
一:繼承基類的方法,並且做出自己的改變或者擴展(代碼重用)
二:聲明某個子類兼容於某基類,定義一個接口類Interface,接口類中定義了一些接口名(就是函數名)且並未實現接口的功能,子類繼承接口類,並且實現接口中的功能

實踐中,繼承的第一種含義意義並不很大,甚至常常是有害的。因爲它使得子類與基類出現強耦合。繼承的第二種含義非常重要。它又叫“接口繼承”。
接口繼承實質上是要求“做出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無需關心具體細節,可一視同仁的處理實現了特定接口的所有對象”——這在程序設計上,叫做歸一化。
歸一化使得高層的外部使用者可以不加區分的處理所有接口兼容的對象集合——就好象linux的泛文件概念一樣,所有東西都可以當文件處理,不必關心它是內存、磁盤、網絡還是屏幕(當然,對底層設計者,當然也可以區分出“字符設備”和“塊設備”,然後做出針對性的設計:細緻到什麼程度,視需求而定)。
依賴倒置原則:高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。換言之,要針對接口編程,而不是針對實現編程

抽象類
 與java一樣,python也有抽象類的概念但是同樣需要藉助模塊實現,抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化,抽象類是一個介於類和接口之間的一個概念,同時具備類和接口的部分特性,可以用來實現歸一化設計

爲什麼要有抽象類
 如果說類是從一堆對象中抽取相同的內容而來的,那麼抽象類就是從一堆類中抽取相同的內容而來的,內容包括數據屬性和函數屬性。
 從設計角度去看,如果類是從現實對象抽象而來的,那麼抽象類就是基於類抽象而來的。
 從實現角度來看,抽象類與普通類的不同之處在於:抽象類中有抽象方法,該類不能被實例化,只能被繼承,且子類必須實現抽象方法。這一點與接口有點類似,但其實是不同的

4、多態
多態指的是一類事物有多種形態。多態性,多態性是指在不考慮實例類型的情況下使用實例。比如:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操作,學生執行的是放學操作,雖然二者消息一樣,但是執行的效果不同

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是動物,只要是動物肯定有talk方法
#於是我們可以不用考慮它們三者的具體是什麼類型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更進一步,我們可以定義一個統一的接口來使用
def func(obj):
    obj.talk()

5、封裝
property屬性
property是一種特殊的屬性,訪問它時會執行一段功能(函數)然後返回值,將一個類的函數定義成特性以後,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然後計算出來的,這種特性的使用方式遵循了統一訪問的原則

class Foo:
    def __init__(self,val):
        self.__NAME=val #將所有的數據屬性都隱藏起來

    @property
    def name(self):
        return self.__NAME #obj.name訪問的是self.__NAME(這也是真實值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在設定值之前進行類型檢查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通過類型檢查後,將值value存放到真實的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #拋出異常'TypeError: 10 must be str'
del f.name #拋出異常'TypeError: Can not delete'

classmethod

staticmethod

發佈了40 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章