1. 程式人生 > >面向對象,類的繼承

面向對象,類的繼承

隱藏 綁定 prop 概念 問控制 ado 描述 保護 事物

面向對象
一種認識世界、分析世界的方法論。將萬事萬物抽象為類。
類class
類是抽象的概念,是萬事萬物的抽象,是一類事物的共同特征的集合。
用計算機語言來描述類,就是屬性和方法的集合。
對象instance、object
對象是類的具象,是一個實體。
對於我們每個人這個個體,都是抽象概念人類的不同的實體。

面向對象3要素

  1. 封裝
    組裝:將數據和操作組裝到一起。
    隱藏數據:對外只暴露一些接口,通過接口訪問對象。比如駕駛員使用汽車,不需要了解汽車的構造細節,只需要知道使用什麽部件怎麽駕駛就行,踩了油門就能跑,可以不了解後面的機動原理。
  2. 繼承
    多復用,繼承來的就不用自己寫了
    多繼承少修改,OCP(Open-closed Principle),使用繼承來改變,來體現個性
  3. 多態
    面向對象編程最靈活的地方,動態綁定

Python的類
定義
class ClassName:
語句塊

  1. 必須使用class關鍵字
  2. 類名必須是用大駝峰命名
  3. 類定義完成後,就產生了一個類對象,綁定到了標識符ClassName上

類對象及類屬性
類對象,類的定義就會生成一個類對象
類的屬性,類定義中的變量和類中定義的方法都是類的屬性
類變量,上例中x是類MyClass的變量
MyClass中,x、foo都是類的屬性, doc 也是類的屬性
foo方法是類的屬性,如同 吃 是人類的方法,但是每一個具體的人才能吃東西,也就是說 吃 是人的實例才能調用
的方法。
foo是方法對象method,不是普通的函數對象function了,它一般要求至少有一個參數。第一個參數可以是

self(self只是個慣用標識符,可以換名字),這個參數位置就留給了self。
self 指代當前實例本身

實例化
a = MyClass() # 實例化
使用上面的語法,在類對象名稱後面加上一個括號,就調用類的實例化方法,完成實例化。
實例化就真正創建一個該類的對象(實例)。
每次實例化後獲得的實例,是不同的實例,即使是使用同樣的參數實例化,也得到不一樣的對象。
Python類實例化後,會自動調用 init 方法。這個方法第一個參數必須留給self,其它參數隨意。
init方法
MyClass()實際上調用的是 init(self) 方法,可以不定義,如果沒有定義會在實例化後隱式調用。
作用:對實例進行初始化

class MyClass:
def init(self):
print(‘init‘)

例對象instance
類實例化後一定會獲得一個對象,就是實例對象。
上例中的tom、jerry就是Person類的實例。
init 方法的第一參數 self 就是指代某一個實例。
類實例化後,得到一個實例對象,實例對象會綁定方法,調用方法時采用jerry.showage()的方式。
但是函數簽名是showage(self),少傳一個參數self嗎?
這個self就是jerry,Python會把方法的調用者作為作為第一參數self的實參傳入。
self.name就是jerry對象的name,name是保存在了jerry對象上,而不是Person類上。所以,稱為實例變量。
特殊屬性 含義
name 對象名
class 對象的類型
dict 對象的屬性的字典
qualname 類的限定名

類方法1在類定義中,使用@classmethod裝飾器修飾的方法
br/>1在類定義中,使用@classmethod裝飾器修飾的方法
4通過cls可以直接操作類的屬性
靜態方法
1在類定義中,使用@staticmethod裝飾器修飾的方法
br/>3cls這個標識符可以是任意合法名稱,但是為了易讀,請不要修改
4通過cls可以直接操作類的屬性
靜態方法
1在類定義中,使用@staticmethod裝飾器修飾的方法
靜態方法,只是表明這個方法屬於這個名詞空間。函數歸在一起,方便組織管理。

類幾乎可以調用所有內部定義的方法,但是調用 普通的方法 時會報錯,原因是第一參數必須是類的實例。
實例也幾乎可以調用所有的方法, 普通的函數 的調用一般不可能出現,因為不允許這麽定義。
總結:
類除了普通方法都可以調用,普通方法需要對象的實例作為第一參數。
實例可以調用所有類中定義的方法(包括類方法、靜態方法),普通方法傳入實例自身,靜態方法和類方法需要找
到實例的類。

訪問控制
私有(Private)屬性
使用雙下劃線開頭的屬性名,就是私有屬性
私有變量的本質:
類定義的時候,如果聲明一個實例變量的時候,使用雙下劃線,Python解釋器會將其改名,轉換名稱為_類名__變量名 的名稱,所以用原來的名字訪問不到了。

保護變量
在變量名前使用一個下劃線,稱為保護變量。
可以看出,這個_age屬性根本就沒有改變名稱,和普通的屬性一樣,解釋器不做任何特殊處理。
這只是開發者共同的約定,看見這種變量,就如同私有變量,不要直接使用。

私有方法的本質
單下劃線的方法只是開發者之間的約定,解釋器不做任何改變。
雙下劃線的方法,是私有方法,解釋器會改名,改名策略和私有變量相同, _類名方法名 。方法變量都在類的 dict__ 中可以找到。
私有成員的總結
在Python中使用 _單下劃線 或者 __ 雙下劃線來標識一個成員被保護或者被私有化隱藏起來。
但是,不管使用什麽樣的訪問控制,都不能真正的阻止用戶修改類的成員。Python中沒有絕對的安全的保護成員
或者私有成員。
因此,前導的下劃線只是一種警告或者提醒,請遵守這個約定。除非真有必要,不要修改或者使用保護成員或者私
有成員,更不要修改它們。

補丁
可以通過修改或者替換類的成員。使用者調用的方式沒有改變,但是,類提供的功能可能已經改變了。
猴子補丁(Monkey Patch):
在運行時,對屬性、方法、函數等進行動態替換。
其目的往往是為了通過替換、修改來增強、擴展原有代碼的能力。

屬性裝飾器
一般好的設計是:把實例的屬性保護起來,不讓外部直接訪問,外部使用getter讀取屬性和setter方法設置屬性

特別註意:使用property裝飾器的時候這三個方法同名
property裝飾器
後面跟的函數名就是以後的屬性名。它就是getter。這個必須有,有了它至少是只讀屬性
setter裝飾器
與屬性名同名,且接收2個參數,第一個是self,第二個是將要賦值的值。有了它,屬性可寫
deleter裝飾器
可以控制是否刪除屬性。很少用
property裝飾器必須在前,setter、deleter裝飾器在後。
property裝飾器能通過簡單的方式,把對方法的操作變成對屬性的訪問,並起到了一定隱藏效果

對象的銷毀
類中可以定義 del 方法,稱為析構函數(方法)。
作用:銷毀類的實例的時候調用,以釋放占用的資源。其中就放些清理資源的代碼,比如釋放連接。
註意這個方法不能引起對象的真正銷毀,只是對象銷毀的時候會自動調用它。
使用del語句刪除實例,引用計數減1。當引用計數為0時,會自動調用 del 方法。
由於Python實現了垃圾回收機制,不能確定對象何時執行垃圾回收。

封裝
面向對象的三要素之一,封裝Encapsulation
封裝
將數據和操作組織到類中,即屬性和方法
將數據隱藏起來,給使用者提供操作(方法)。使用者通過操作就可以獲取或者修改數據。getter和setter。
通過訪問控制,暴露適當的數據和操作給用戶,該隱藏的隱藏起來,例如保護成員或私有成員。

類的繼承
基本概念
面向對象三要素之一,繼承Inheritance
人類和貓類都繼承自動物類。
個體繼承自父母,繼承了父母的一部分特征,但也可以有自己的個性。
在面向對象的世界中,從父類繼承,就可以直接擁有父類的屬性和方法,這樣可以減少代碼、多復用。子類可以定
義自己的屬性和方法。

繼承
class Cat(Animal) 這種形式就是從父類繼承,括號中寫上繼承的類的列表。
繼承可以讓子類從父類獲取特征(屬性和方法)
父類
Animal就是Cat的父類,也稱為基類、超類。
子類
Cat就是Animal的子類,也稱為派生類。

定義
格式如下
class 子類名(基類1[,基類2,...]):
語句塊

特殊屬性和方法 含義 示例
base 類的基類
bases 類的基類元組
mro 顯示方法查找順序,基類的元組
mro()方法 同上,返回列表 int.mro()
subclasses() 類的子類列表 int.subclasses()

從父類繼承,自己沒有的,就可以到父類中找。
私有的都是不可以訪問的,但是本質上依然是改了名稱放在這個屬性所在類或實例的dict中。知道這個新名稱
就可以直接找到這個隱藏的變量,這是個黑魔法技巧,慎用。
總結
繼承時,公有的,子類和實例都可以隨意訪問;私有成員被隱藏,子類和實例不可直接訪問,但私有變量所在的類
內的方法中可以訪問這個私有變量。
Python通過自己一套實現,實現和其它語言一樣的面向對象的繼承機制。
屬性查找順序
實例的dict ===》 類dict ===如果有繼承===》 父類 dict
如果搜索這些地方後沒有找到就會拋異常,先找到就立即返回了。

方法的重寫、覆蓋override
技術分享圖片

面向對象,類的繼承