Python的继承多态
Python的繼承多態(tài)
文章目錄
- Python的繼承多態(tài)
- 一、私有屬性和私有方法
- 01. 應(yīng)用場(chǎng)景及定義方式
- 02. 偽私有屬性和私有方法
 
- 二、單例
- 01. 單例設(shè)計(jì)模式
- 單例設(shè)計(jì)模式的應(yīng)用場(chǎng)景
 
- 02. `__new__` 方法
- 03. Python 中的單例
- 只執(zhí)行一次初始化工作
 
 
- 三、繼承
- 01. 單繼承
- 1.1 繼承的概念、語法和特點(diǎn)
- 1) 繼承的語法
- 2) 專業(yè)術(shù)語
- 3) 繼承的傳遞性
 
- 1.2 方法的重寫
- 1) 覆蓋父類的方法
- 2) 對(duì)父類方法進(jìn)行 **擴(kuò)展**
- 關(guān)于 `super`
- 調(diào)用父類方法的另外一種方式
 
 
- 1.3 父類的 私有屬性 和 私有方法
 
- 02. 多繼承
- 2.1 多繼承的使用注意事項(xiàng)
- Python 中的 MRO —— 方法搜索順序(知道)
 
- 2.2 新式類與舊式(經(jīng)典)類
 
 
- 多態(tài)
- 多態(tài)案例演練
 
一、私有屬性和私有方法
01. 應(yīng)用場(chǎng)景及定義方式
應(yīng)用場(chǎng)景
- 在實(shí)際開發(fā)中,對(duì)象 的 某些屬性或方法 可能只希望 在對(duì)象的內(nèi)部被使用,而 不希望在外部被訪問到
- 私有屬性 就是 對(duì)象 不希望公開的 屬性
- 私有方法 就是 對(duì)象 不希望公開的 方法
定義方式
- 在 定義屬性或方法時(shí),在 屬性名或者方法名前 增加 兩個(gè)下劃線,定義的就是 私有 屬性或方法
02. 偽私有屬性和私有方法
提示:在日常開發(fā)中,不要使用這種方式,訪問對(duì)象的 私有屬性 或 私有方法
Python 中,并沒有 真正意義 的 私有
- 在給 屬性、方法 命名時(shí),實(shí)際是對(duì) 名稱 做了一些特殊處理,使得外界無法訪問到
- 處理方式:在 名稱 前面加上 _類名 => _類名__名稱
二、單例
01. 單例設(shè)計(jì)模式
-  設(shè)計(jì)模式 - 設(shè)計(jì)模式 是 前人工作的總結(jié)和提煉,通常,被人們廣泛流傳的設(shè)計(jì)模式都是針對(duì) 某一特定問題 的成熟的解決方案
- 使用 設(shè)計(jì)模式 是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
 
-  單例設(shè)計(jì)模式 - 目的 —— 讓 類 創(chuàng)建的對(duì)象,在系統(tǒng)中 只有 唯一的一個(gè)實(shí)例
- 每一次執(zhí)行 類名() 返回的對(duì)象,內(nèi)存地址是相同的
 
單例設(shè)計(jì)模式的應(yīng)用場(chǎng)景
- 音樂播放 對(duì)象
- 回收站 對(duì)象
- 打印機(jī) 對(duì)象
- ……
02. __new__ 方法
- 使用 類名() 創(chuàng)建對(duì)象時(shí),Python 的解釋器 首先 會(huì) 調(diào)用 __new__ 方法為對(duì)象 分配空間
- __new__ 是一個(gè) 由 object 基類提供的 內(nèi)置的靜態(tài)方法,主要作用有兩個(gè): 
- 在內(nèi)存中為對(duì)象 分配空間
 
- 返回 對(duì)象的引用
重寫 __new__ 方法 的代碼非常固定!
- 重寫 __new__ 方法 一定要 return super().__new__(cls)
- 否則 Python 的解釋器 得不到 分配了空間的 對(duì)象引用,就不會(huì)調(diào)用對(duì)象的初始化方法
- 注意:__new__ 是一個(gè)靜態(tài)方法,在調(diào)用時(shí)需要 主動(dòng)傳遞 cls 參數(shù)
示例代碼
class MusicPlayer(object):def __new__(cls, *args, **kwargs):# 如果不返回任何結(jié)果,return super().__new__(cls)def __init__(self):print("初始化音樂播放對(duì)象")player = MusicPlayer()print(player)03. Python 中的單例
- 單例 —— 讓 類 創(chuàng)建的對(duì)象,在系統(tǒng)中 只有 唯一的一個(gè)實(shí)例
- 定義一個(gè) 類屬性,初始值是 None,用于記錄 單例對(duì)象的引用
- 重寫 __new__ 方法
- 如果 類屬性 is None,調(diào)用父類方法分配空間,并在類屬性中記錄結(jié)果
- 返回 類屬性 中記錄的 對(duì)象引用
只執(zhí)行一次初始化工作
- 在每次使用 類名() 創(chuàng)建對(duì)象時(shí),Python 的解釋器都會(huì)自動(dòng)調(diào)用兩個(gè)方法: - __new__ 分配空間
- __init__ 對(duì)象初始化
 
- 在上一小節(jié)對(duì) __new__ 方法改造之后,每次都會(huì)得到 第一次被創(chuàng)建對(duì)象的引用
- 但是:初始化方法還會(huì)被再次調(diào)用
需求
- 讓 初始化動(dòng)作 只被 執(zhí)行一次
解決辦法
三、繼承
面向?qū)ο笕筇匦?/strong>
01. 單繼承
1.1 繼承的概念、語法和特點(diǎn)
繼承的概念:子類 擁有 父類 的所有 方法 和 屬性
 
1) 繼承的語法
class 類名(父類名):pass- 子類 繼承自 父類,可以直接 享受 父類中已經(jīng)封裝好的方法,不需要再次開發(fā)
- 子類 中應(yīng)該根據(jù) 職責(zé),封裝 子類特有的 屬性和方法
2) 專業(yè)術(shù)語
- Dog 類是 Animal 類的子類,Animal 類是 Dog 類的父類,Dog 類從 Animal 類繼承
- Dog 類是 Animal 類的派生類,Animal 類是 Dog 類的基類,Dog 類從 Animal 類派生
3) 繼承的傳遞性
- C 類從 B 類繼承,B 類又從 A 類繼承
- 那么 C 類就具有 B 類和 A 類的所有屬性和方法
子類 擁有 父類 以及 父類的父類 中封裝的所有 屬性 和 方法
提問
哮天犬 能夠調(diào)用 Cat 類中定義的 catch 方法嗎?
答案
不能,因?yàn)?哮天犬 和 Cat 之間沒有 繼承 關(guān)系
1.2 方法的重寫
- 子類 擁有 父類 的所有 方法 和 屬性
- 子類 繼承自 父類,可以直接 享受 父類中已經(jīng)封裝好的方法,不需要再次開發(fā)
應(yīng)用場(chǎng)景
- 當(dāng) 父類 的方法實(shí)現(xiàn)不能滿足子類需求時(shí),可以對(duì)方法進(jìn)行 重寫(override)
重寫 父類方法有兩種情況:
1) 覆蓋父類的方法
- 如果在開發(fā)中,父類的方法實(shí)現(xiàn) 和 子類的方法實(shí)現(xiàn),完全不同
- 就可以使用 覆蓋 的方式,在子類中 重新編寫 父類的方法實(shí)現(xiàn)
具體的實(shí)現(xiàn)方式,就相當(dāng)于在 子類中 定義了一個(gè) 和父類同名的方法并且實(shí)現(xiàn)
重寫之后,在運(yùn)行時(shí),只會(huì)調(diào)用 子類中重寫的方法,而不再會(huì)調(diào)用 父類封裝的方法
2) 對(duì)父類方法進(jìn)行 擴(kuò)展
- 如果在開發(fā)中,子類的方法實(shí)現(xiàn) 中 包含 父類的方法實(shí)現(xiàn) - 父類原本封裝的方法實(shí)現(xiàn) 是 子類方法的一部分
 
- 就可以使用 擴(kuò)展 的方式
- 在子類中 重寫 父類的方法
- 在需要的位置使用 super().父類方法 來調(diào)用父類方法的執(zhí)行
- 代碼其他的位置針對(duì)子類的需求,編寫 子類特有的代碼實(shí)現(xiàn)
關(guān)于 super
- 在 Python 中 super 是一個(gè) 特殊的類
- super() 就是使用 super 類創(chuàng)建出來的對(duì)象
- 最常 使用的場(chǎng)景就是在 重寫父類方法時(shí),調(diào)用 在父類中封裝的方法實(shí)現(xiàn)
調(diào)用父類方法的另外一種方式
在 Python 2.x 時(shí),如果需要調(diào)用父類的方法,還可以使用以下方式:
父類名.方法(self)- 這種方式,目前在 Python 3.x 還支持這種方式
- 這種方法 不推薦使用,因?yàn)橐坏?父類發(fā)生變化,方法調(diào)用位置的 類名 同樣需要修改
提示
- 在開發(fā)時(shí),父類名 和 super() 兩種方式不要混用
- 如果使用 當(dāng)前子類名 調(diào)用方法,會(huì)形成遞歸調(diào)用,出現(xiàn)死循環(huán)
1.3 父類的 私有屬性 和 私有方法
- 私有屬性、方法 是對(duì)象的隱私,不對(duì)外公開,外界 以及 子類 都不能直接訪問
- 私有屬性、方法 通常用于做一些內(nèi)部的事情
示例
- B 的對(duì)象不能直接訪問 __num2 屬性
- B 的對(duì)象不能在 demo 方法內(nèi)訪問 __num2 屬性
- B 的對(duì)象可以在 demo 方法內(nèi),調(diào)用父類的 test 方法
- 父類的 test 方法內(nèi)部,能夠訪問 __num2 屬性和 __test 方法
02. 多繼承
概念
- 子類 可以擁有 多個(gè)父類,并且具有 所有父類 的 屬性 和 方法
- 例如:孩子 會(huì)繼承自己 父親 和 母親 的 特性
語法
class 子類名(父類名1, 父類名2...)pass2.1 多繼承的使用注意事項(xiàng)
問題的提出
- 如果 不同的父類 中存在 同名的方法,子類對(duì)象 在調(diào)用方法時(shí),會(huì)調(diào)用 哪一個(gè)父類中的方法呢?
提示:開發(fā)時(shí),應(yīng)該盡量避免這種容易產(chǎn)生混淆的情況! —— 如果 父類之間 存在 同名的屬性或者方法,應(yīng)該 盡量避免 使用多繼承
Python 中的 MRO —— 方法搜索順序(知道)
- Python 中針對(duì) 類 提供了一個(gè) 內(nèi)置屬性 __mro__ 可以查看 方法 搜索順序
- MRO 是 method resolution order,主要用于 在多繼承時(shí)判斷 方法、屬性 的調(diào)用 路徑
輸出結(jié)果
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)- 在搜索方法時(shí),是按照 __mro__ 的輸出結(jié)果 從左至右 的順序查找的
- 如果在當(dāng)前類中 找到方法,就直接執(zhí)行,不再搜索
- 如果 沒有找到,就查找下一個(gè)類 中是否有對(duì)應(yīng)的方法,如果找到,就直接執(zhí)行,不再搜索
- 如果找到最后一個(gè)類,還沒有找到方法,程序報(bào)錯(cuò)
2.2 新式類與舊式(經(jīng)典)類
object 是 Python 為所有對(duì)象提供的 基類,提供有一些內(nèi)置的屬性和方法,可以使用 dir 函數(shù)查看
-  新式類:以 object 為基類的類,推薦使用 
-  經(jīng)典類:不以 object 為基類的類,不推薦使用 
-  在 Python 3.x 中定義類時(shí),如果沒有指定父類,會(huì) 默認(rèn)使用 object 作為該類的 基類 —— Python 3.x 中定義的類都是 新式類 
-  在 Python 2.x 中定義類時(shí),如果沒有指定父類,則不會(huì)以 object 作為 基類 
新式類 和 經(jīng)典類 在多繼承時(shí) —— 會(huì)影響到方法的搜索順序
為了保證編寫的代碼能夠同時(shí)在 Python 2.x 和 Python 3.x 運(yùn)行!
 今后在定義類時(shí),如果沒有父類,建議統(tǒng)一繼承自 object
多態(tài)
面向?qū)ο笕筇匦?/strong>
- 定義類的準(zhǔn)則
- 設(shè)計(jì)類的技巧
- 子類針對(duì)自己特有的需求,編寫特定的代碼
- 多態(tài) 可以 增加代碼的靈活度
- 以 繼承 和 重寫父類方法 為前提
- 是調(diào)用方法的技巧,不會(huì)影響到類的內(nèi)部設(shè)計(jì)
多態(tài)案例演練
需求
- 普通狗只是簡(jiǎn)單的玩耍
- 哮天犬需要在天上玩耍
- 在方法內(nèi)部,直接讓 狗對(duì)象 調(diào)用 game 方法
 
案例小結(jié)
- Person 類中只需要讓 狗對(duì)象 調(diào)用 game 方法,而不關(guān)心具體是 什么狗 - game 方法是在 Dog 父類中定義的
 
- 在程序執(zhí)行時(shí),傳入不同的 狗對(duì)象 實(shí)參,就會(huì)產(chǎn)生不同的執(zhí)行效果
多態(tài) 更容易編寫出出通用的代碼,做出通用的編程,以適應(yīng)需求的不斷變化!
class Dog(object):def __init__(self, name):self.name = namedef game(self):print("%s 蹦蹦跳跳的玩耍..." % self.name)class XiaoTianDog(Dog):def game(self):print("%s 飛到天上去玩耍..." % self.name)class Person(object):def __init__(self, name):self.name = namedef game_with_dog(self, dog):print("%s 和 %s 快樂的玩耍..." % (self.name, dog.name))# 讓狗玩耍dog.game()# 1. 創(chuàng)建一個(gè)狗對(duì)象 # wangcai = Dog("旺財(cái)") wangcai = XiaoTianDog("飛天旺財(cái)")# 2. 創(chuàng)建一個(gè)小明對(duì)象 xiaoming = Person("小明")# 3. 讓小明調(diào)用和狗玩的方法 xiaoming.game_with_dog(wangcai)總結(jié)
以上是生活随笔為你收集整理的Python的继承多态的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Python中的高阶变量
- 下一篇: Python中的文件操作和异常
