最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

5th Python面向?qū)ο蠡A(chǔ)

2021-04-09 17:22 作者:MoNanGo  | 我要投稿

5.1 引子

人狗大戰(zhàn)的實例

需求:

  • 多條狗,每個狗有名字,品種,攻擊力

  • 可以有多個人

  • 狗可以咬人,人可以打狗

我們可能會這樣寫:

那我們?nèi)绻卸鄺l狗,我就需要寫多個字典,而且還是要手動創(chuàng)建的,所以我們想到了函數(shù),創(chuàng)建一個dog(name, d_type),這樣我們要創(chuàng)建就調(diào)用這個函數(shù)即可,eg:dog('zs', 'big'),就不用手動創(chuàng)建了。

那隨著產(chǎn)品的功能升級,現(xiàn)在需要狗不能調(diào)用人打狗的動作,人不能調(diào)用狗咬人的動作,我們可以加一個判斷來實現(xiàn);人又分男人和女人,女人可以生孩子,男人不可以,我們就又要講男人和女人的定義函數(shù)分開定義,而且又要新加判斷使生孩子只能女人調(diào)用。。。。。。

可以看出,很麻煩。所以我們需要換一個思路。

5.2 編程范式——面向過程

簡單介紹

面向過程,核心是“過程”這兩個字。我們之前寫的代碼都是面向過程的編程方式(編程范式),就是我們一步一步確定先干什么在什么,然后用函數(shù)一個一個功能的實現(xiàn),最后實現(xiàn)了我們的大目標。

總結(jié)一下,面向過程就是將一個大問題分解成多個小問題然后一一解決。

優(yōu)點

解決問題的流程簡單化,知道一步一步該干嘛,比如Python入門要輸出只需一個print()就好,但如果是Java的話,你得先寫個public static void main這樣的框架。eg:我們要實現(xiàn)修改文件,很容易想到步驟:讀取文件數(shù)據(jù) -> 判斷數(shù)據(jù) -> 數(shù)據(jù)寫入 -> 文件替換。

缺點

通過我們前面寫出來的代碼我們應(yīng)該可以感覺的到,這樣寫出來的程序擴展性不是很強。很多函數(shù)都是與其他函數(shù)牽扯在一起的。函數(shù)一旦寫多,找都找的不方便,也不便于維護,特別是那些需要功能需要經(jīng)常變動,而且需要不斷更新迭代和維護的場景。

應(yīng)用場景

面向過程一般用在代碼更新迭代很少的場景,其他場景最好用面向?qū)ο蟮木幊谭妒健g:Linux內(nèi)核、git等等

5.3 編程范式——面向?qū)ο?/h1>

簡單介紹

編程范式最常用的就是面向過程和面向?qū)ο蟆C嫦驅(qū)ο蟮暮诵木褪?span id="s0sssss00s" class="md-pair-s " style="">類與對象。面向?qū)ο缶褪菍嶋H需求抽象成一個個對象,什么是對象?

說對象之前我們要說說類(class),我們可以類似理解為種類,比如人就是一個對象,包括男人、女人、老人、小孩等等等等;動物也是一個對象,包括大象、獅子、兔子等等。

和對象這樣泛指的概念相對應(yīng)的就是對象(object)。對象就是一個指定的一個東西,可以說類是由很多的對象構(gòu)成的。eg:男人是由zm、wzw、yz、zk等等千千萬萬的對象組成的。

然后對象到實例的轉(zhuǎn)化過程就叫做實例化,代碼就和上面提到的代碼很像。eg:Dog('zs', 'big')

PS:如果不理解可以類比數(shù)學(xué)中集合和構(gòu)成集合的每個數(shù)來理解。一個類就是一個集合,集合里裝的許多數(shù)就是類下實例化出來的一個個對象。

優(yōu)點

解決了面向過程可擴展性較差的問題,擴展性大大提高。后面的學(xué)習(xí)過程中我們還會再說。

缺點

編程的復(fù)雜度遠高于面向過程,如果不了解面向?qū)ο缶蜕鲜?,再基于面向?qū)ο笤O(shè)計程序,就極容易會出現(xiàn)過度設(shè)計的問題。

應(yīng)用場景

因為面向?qū)ο蟮碾y度,我們在管理Linux系統(tǒng)的shell腳本程序中就會應(yīng)用面向過程的方法。在軟件開發(fā)等方向中面向?qū)ο?/strong>應(yīng)用廣泛。

5.4 類與對象

定義語法

我們先寫一個簡單的類與對象的語法實例:



需要注意的點有:

  • 類中可以寫任何的python代碼,這些代碼在類定義的階段便會執(zhí)行,因而會產(chǎn)生新的名稱空間,用來存放類的變量名與函數(shù)名,可以通過類名.__dict__來查看

  • 類中定義的名字都是類的屬性,.是訪問屬性的語法

  • 對于經(jīng)典類來說我們可以通過蓋子點操作類名稱空間的名字,但新式類有限制(經(jīng)典類和新式類的區(qū)別)

類的使用

  • 引用類的屬性:

  • 實例化類,得到一個對象:

  • __init__方法:

對象的使用

對象的增刪改查和類的增刪改查很類似。



關(guān)于類的設(shè)置

  • 每個程序員考慮的角度不同時,對于同一個需求定義的類可能截然不同

  • 現(xiàn)實中的類并不完全等于程序中的類,比如人這個類,在程序中可能需要分成老師類、學(xué)生類等等

  • 程序中創(chuàng)建的類可能在現(xiàn)實生活中不存在,比如策略類這個很常用的類,還比如MapReduce中的Mapper和Reducer這兩個核心抽象類

經(jīng)典類和新式類

經(jīng)典類

?class A: # 經(jīng)典類
? ? ?pass

新式類

?class B(object): # 新式類
? ? ?pass

Python中創(chuàng)建的一切都是對象,object可以理解為Python最原始的類,所有對象都是它衍生出來的。

我們一般寫的都是經(jīng)典類,在多繼承那里我們會詳細說它們兩個的區(qū)別。

5.5 實例屬性&公共屬性

我們將上面的Student類修繕一下:


我們創(chuàng)建兩個對象

stu1 = Student('zm', 19, 'male')

stu2 = Student('wzw', 23, 'male')

我們輸出比較id(stu1.school)id(stu2.school),我們會發(fā)現(xiàn)兩個對象調(diào)用的school屬性的id都是一樣的,我們就稱school這樣的屬性是公有屬性(類屬性)。

那我們在__init__()中也定義了一些屬性,這里面的屬性我們就稱它們?yōu)閷嵗龑傩裕ㄒ卜Q成員屬性),原因前面我們提過,__init__()是對象創(chuàng)建過后才將數(shù)據(jù)賦值到屬性上的。

類里面的函數(shù)之間的數(shù)據(jù)是不相關(guān)的,要想實現(xiàn)有相互調(diào)用的數(shù)據(jù),就需要把函數(shù)里面的值存到實例里,那就要將兩個值與實例進行綁定,那我們就用到了self。

self代表實例(一個創(chuàng)建的對象,不是類!)本身,在stu1.hello()調(diào)用實例方法時,他默認的就執(zhí)行stu1.hello(stu1),然后函數(shù)中的self.school就是stu2.school。那這樣的解釋也可以用來解釋__init__(self)里面的self.name = name這樣的語句就是將自己內(nèi)部的數(shù)據(jù)和實例進行綁定,這樣hello()里面就可以調(diào)用__init__()里面的name參數(shù)了。

應(yīng)用情況

一般的,很多對象的屬性都一樣,那就可以用公共屬性。而且公共屬性如果被實例化以后,單獨的實例修改后,就變成了給該實例創(chuàng)建一個新的實例屬性,不會影響到公共屬性的值。常見的屬性有國籍、所屬學(xué)校等等。

像姓名、年齡、性別這些基本每個對象都不一樣的屬性,我們一般用實例屬性。

下面就用上面的Student類做eg:



5.6 類之間的依賴關(guān)系

就像人和人之間存在很多種關(guān)系,類與類之間也有關(guān)系,類與類之間的關(guān)系一般分為下面5種:

  1. 依賴關(guān)系:你每個月都找父母要生活費的時候,你和父母的關(guān)系;

  2. 關(guān)聯(lián)關(guān)系:你和你基友或者閨蜜;

  3. 組合關(guān)系:比聚合關(guān)系更加緊密的關(guān)系,比如大腦和心臟,人死了,所有器官都會死;

  4. 聚合關(guān)系:比如電腦的各個部件,電腦壞了有的部件還是正常的;

  5. 繼承關(guān)系:類的三大特性之一,子承父業(yè)。

依賴關(guān)系

關(guān)聯(lián)關(guān)系

那我們可以實現(xiàn)一次就雙向關(guān)聯(lián)嘛?

答案是可以的,我們可以將關(guān)聯(lián)關(guān)系單獨放在一個類中,如這一段代碼:


組合關(guān)系

我們接著一開始說的人狗大戰(zhàn),我們增加一個武器類,然后實現(xiàn)武器與人捆綁。


這里武器和人就是組合關(guān)系,武器自己單獨不會被使用,只有創(chuàng)建一個人的對象時,才會被捆綁創(chuàng)建。

可以說,如果兩個對象之間有什么數(shù)據(jù)的交互,那這兩個對象就是組合關(guān)系。

5.7 面向?qū)ο笕筇匦灾^承

繼承就是子承父業(yè),目的就是減少重復(fù)的代碼。具體怎么減少,那我們在代碼中就可以感覺的到。有了繼承的概念就有了派生類的概念,派生類就是子類,只是必須既有父類特性又有自己的一些私有特性。

比如現(xiàn)在我們有人、豬、狗三個類,他們都屬于動物這個類,那我們就可以將人、豬、狗的一些共性寫到動物類的屬性中,這樣就不用寫三遍重復(fù)的代碼了。

繼承的語法是括號:

上面的代碼中,Person和Dog是繼承了Animal類的,這樣Person和Dog就可以不用各自單獨定義__init__()等相關(guān)重復(fù)代碼了,直接調(diào)用Animal的屬性和方法即可。

在上面的基礎(chǔ)上,子類也可以定義只屬于自己的方法。

那除了這些,子類還可以重寫父類的方法和屬性,這樣也不會影響到父類的方法和屬性。

那我們可以重寫父類的屬性和方法,那父類的__init__()子類是否可以重寫呢?這點我們單獨放在一點里說,和剛才上面說的有點不一樣。

重寫父類的__init__()

直接上代碼:

代碼中都和大家說的很清楚了,我們只需要注意別忘了給父類的方法傳入self就好了。

當然,父類__init__()的重寫不止上面代碼所示的一種方法,上面的方法在python2中經(jīng)常使用,python3常用的方法是通過super()來重寫。

還有一種super的寫法:super().__init__(name, age, sex),這個相對于第二種比較方便,所以也比較常用。

當然,super()不會只能調(diào)用父類的__init__(),父類的所有屬性和方法都可以調(diào)用。調(diào)用的語法是和__init__()一樣的,比如super().type_animal、super().say_info()。

我們可以發(fā)現(xiàn),就是把Animal換成super()而已。super()還有其他的一些應(yīng)用,super()的用處還在下面要說的多繼承中有所體現(xiàn)。

多繼承

所謂多繼承就是一個類有多個父類,比如如下的代碼:

MonkeyKing這個類在代碼中就是多繼承,同時可以調(diào)用Immortal和Monkey兩個父類的屬性和方法。

在各類主流語言中,C++、Python是支持多繼承的,Java是不支持的。因為多繼承有時可能會使程序調(diào)試變的復(fù)雜。

那多繼承就會引發(fā)一個問題,如果子類調(diào)用父類中有相同名字的方法或者屬性時,到底運行哪一個?比如:

我們看輸出是神仙在打架,我們換一下MonkeyKing后面括號里的繼承順序,就可以看出輸出就會是猴子在打架。我們就可以得出繼承順序是從左到右。

但是多繼承的順序機制沒有這么簡單,我們再改變一下代碼:

那關(guān)系就比較復(fù)雜了,我們該如何確定查找邏輯呢?

這個繼承的關(guān)系我們用圖畫出來就會看出是類似一個樹的結(jié)構(gòu)。我們常見的樹結(jié)構(gòu)的查找邏輯,有深度優(yōu)先算法廣度優(yōu)先算法。

我們通過注釋輸出類的方法一遍一遍的輸出,我們會發(fā)現(xiàn)繼承順序是Monkey->MonkeyBase->Immortal->Immortal。如果我們再讓Animal作為MonkeyBase的父類,順序就是Monkey->MonkeyBase->Animal->Immortal->Immortal。那我們就可以得出,Python類的繼承順序是按照深度優(yōu)先算法來繼承的。

不過,但這里還沒有結(jié)束。我們再繼續(xù)說說。

我們前面說了經(jīng)典類和新式類。在Python2中,這兩個類的查找法是不一樣的:經(jīng)典類采用深度優(yōu)先查找,而新式類采用廣度優(yōu)先查找。不過到了Python3,無論是經(jīng)典類還是新式類,都是按廣度優(yōu)先查找的。(和上面的結(jié)論沖突,繼續(xù)看C3算法就好)

Python2默認都是經(jīng)典類,Python3默認都是新式類,所以我們不用每次都寫object,了解了就行。

多繼承的C3算法

不過等等,我們實踐證明出來了python3是深度優(yōu)先,而上面又說是按廣度優(yōu)先,那到底是按照什么來查找?睜著眼說瞎話?

先別急,我們現(xiàn)在再改變一下代碼,讓ImmortalBase和MonkeyBase同時繼承Base類。那我們再重復(fù)剛才的實踐,我們就會發(fā)現(xiàn),順序變成了Monkey->MonkeyBase->Immortal->ImmortalBase->Base。

小朋友你是否有很多問號?????這到底是深度還是廣度?

其實,Python的繼承算法是C3算法,比較復(fù)雜,接下來我們慢慢來介紹。

我們再給出一個繼承關(guān)系復(fù)雜的一段代碼:

我們可以看到輸出的繼承順序是(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B2'>, <class '__main__.C2'>, <class 'object'>)

為了較好理解,我們畫成圖來給大家理解:


嗯????小朋友你是否又有很多問號?

到這里,我們只要知道反正肯定不是深度或者廣度,清楚C3對于小白來說也沒什么用,而且C3是Python比較底層的東西了,不用理解的太深入。在Python的官網(wǎng)以及其他的一些資料上都寫了Python是深度優(yōu)先查找,我們知道就好了。

總結(jié)

一般代碼都繼承都不會寫到這么復(fù)雜,不然調(diào)式什么的都不好調(diào)試。

然后還需要提一下的就是,雖然python3默認都是新式類,但是官方的推薦還是要寫object的,所以我們以后就寫一下就好了,專業(yè)一點。

class A(object):

????pass

5.8 面向?qū)ο笕筇匦灾庋b

封裝是什么

封裝可以被認為是一個保護的屏障,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機訪問。想要訪問就必須通過嚴格的接口控制。

適當?shù)姆庋b可以讓程序代碼更容易被維護,也加強了代碼數(shù)據(jù)的安全性。

封裝的優(yōu)點

  1. 良好的封裝能夠減少耦合;

  2. 類內(nèi)部的結(jié)構(gòu)可以自由修改;

  3. 可以對成員變成進行更精確地控制;

  4. 隱藏信息,實現(xiàn)細節(jié)。

封裝的原則

  • 將不需要向外部隨意操作的數(shù)據(jù)進行封裝。

舉些栗子

比如人狗大戰(zhàn)的人和狗的生命值這個屬性,肯定是不能讓外部的代碼隨便修改的,所以我們需要封裝生命值,這些封裝的了屬性就叫私有屬性。

私有屬性不能直接調(diào)用,只能通過類內(nèi)部的一些方法來調(diào)用,這些方法即是前面說到的一些訪問封裝(私有屬性被封裝的東西等)的接口。

外部只能通過接口來操作封裝的東西,你能進行什么操作(刪除、獲取、修改等)全靠類給你提供了什么接口。


封裝的不止可以有屬性,還可以封裝方法,比如我們我們增加一個呼吸。


如果在外部真的想獲取被封裝的東西,語法是實例名._類名+封裝東西的名稱,可以執(zhí)行新增、修改、獲取、刪除等操作。

p._Person__breath() print(p._Person__life_val)

當然,pycharm可能會警告,但是輸出還是會正常輸出的,只是最好不要這么用,不然你封裝也就沒意義了。

5.9 面向?qū)ο笕筇匦灾鄳B(tài)

什么是多態(tài)

現(xiàn)在有一個動物類Animal,子類有蛇、狗等,他們都繼承Animal的eat()方法,但是蛇和狗的吃都是不一樣的,比如蛇是吞,狗是一部分一部分的咬。那這種調(diào)用同一個接口,而表示形式不同的現(xiàn)象,就叫做多態(tài)。

統(tǒng)一函數(shù)接口實現(xiàn)多態(tài)


抽象類實現(xiàn)多態(tài)(最常用)


這里的代碼除了raise那句代碼我們下一章介紹,其他的代碼我們應(yīng)該都可以理解的。多態(tài)的應(yīng)用在網(wǎng)絡(luò)編程的原理普遍用到,雖然我們實際用到的不多,但是確實是一個很重點的點,畢竟面向?qū)ο笕筇攸c之一。

這一篇我將成片的代碼段變成了截圖形式,大家看看什么感覺,如果還是習(xí)慣之前灰色處理的話,下一篇就還原回來哈。

有什么Python代碼或者其他問題可以私信問我或者在下面留言,Python課程設(shè)計我也偶爾可以有償幫做,祝大家變得更強[狗頭]

剩下的就是和上一篇文章末尾一樣要說的,我就當成套話了。

套話:因為小破站上的文本格式對演示代碼極其不友好,而且自己平時的筆記是通過Markdown語法來記錄的,在格式上和美觀程度上不是很好看,如果你看的不習(xí)慣,就去下載一個Typora(或者支持markdown語法的應(yīng)用),我這里給出md文件的迅雷和百度網(wǎng)盤鏈接,然后用Typora打開文件看就好了。


迅雷網(wǎng)盤

鏈接:https://pan.xunlei.com/s/VMXpt1TptGyPt3YPLs1fEA5eA1
提取碼:s7ei

百度網(wǎng)盤

鏈接:https://pan.baidu.com/s/1jUYcrmv27e6VIO8kVGu9ng
提取碼:1mtr


5th Python面向?qū)ο蠡A(chǔ)的評論 (共 條)

分享到微博請遵守國家法律
东海县| 子长县| 田东县| 繁昌县| 稻城县| 保德县| 渑池县| 瓮安县| 沙田区| 湖州市| 新乡县| 壤塘县| 花莲市| 朝阳市| 海门市| 铅山县| 内乡县| 新乡市| 博兴县| 泰安市| 高唐县| 江孜县| 布尔津县| 班玛县| 六枝特区| 云浮市| 汝城县| 公安县| 顺昌县| 延寿县| 威宁| 华宁县| 夏邑县| 阿巴嘎旗| 江阴市| 鄂托克旗| 临邑县| 利辛县| 宝坻区| 潼南县| 葫芦岛市|