Day06的課程要點(diǎn)記錄
詳細(xì)教程地址:Day6 - 面向?qū)ο髮W(xué)習(xí)
上節(jié)補(bǔ)遺 - Subprocess
模塊
os.system # 輸出命令結(jié)果到屏幕拯爽,返回命令執(zhí)行狀態(tài)
os.popen("dir").read() # 會(huì)保存命令的執(zhí)行結(jié)果輸出
subprocess
模塊主要用于替換幾個(gè)舊模塊:os.system
, os.spawn*
常用subprocess
方法示例
subprocess.run() # Python 3.5 后才出現(xiàn)的方法
執(zhí)行命令妒蛇,返回命令執(zhí)行狀態(tài) 曙蒸, 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"]) # 命令用列表單個(gè)傳入鲤屡,或者完整輸入字符串老充,用`shell=True`來執(zhí)行操作系統(tǒng)執(zhí)行。該方法效果類似os.system
#執(zhí)行命令土至,如果命令結(jié)果為0购对,就正常返回,否則拋異常
>>> subprocess.check_call(["ls", "-l"])
0
#接收字符串格式命令陶因,返回元組形式骡苞,第1個(gè)元素是執(zhí)行狀態(tài),第2個(gè)是命令結(jié)果
>>> subprocess.getstatusoutput('ls /bin/ls') # 最常用
(0, '/bin/ls')
#接收字符串格式命令坑赡,并返回結(jié)果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
#執(zhí)行命令烙如,并返回結(jié)果么抗,注意是返回結(jié)果毅否,不是打印,下例結(jié)果返回給res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'
上面那些方法蝇刀,底層都是封裝的subprocess.Popen
poll() # 檢查是否執(zhí)行完畢螟加,根據(jù)狀態(tài)返回相應(yīng)值
Check if child process has terminated. Returns returncode
wait()
Wait for child process to terminate. Returns returncode attribute.
terminate() 殺掉所啟動(dòng)進(jìn)程
communicate() 等待任務(wù)結(jié)束
stdin 標(biāo)準(zhǔn)輸入
stdout 標(biāo)準(zhǔn)輸出
stderr 標(biāo)準(zhǔn)錯(cuò)誤
pid
The process ID of the child process.
例子:
stdin
, stdout
等,必須要加參數(shù)subprocess.PIPE
吞琐,才能read()
類似操作系統(tǒng)中捆探,不同進(jìn)程的程序互相傳數(shù)據(jù)需要通過管道
>>> p = subprocess.Popen("df -h|grep disk",stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
>>> p.stdout.read()
b'/dev/disk1 465Gi 64Gi 400Gi 14% 16901472 104938142 14% /\n'
調(diào)用subprocess.run(...)
是推薦的常用方法,在大多數(shù)情況下能滿足需求站粟,但如果你可能需要進(jìn)行一些復(fù)雜的與系統(tǒng)的交互的話黍图,你還可以用subprocess.Popen()
,語法如下:
p = subprocess.Popen("find / -size +1000000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())
可用參數(shù)
- args:shell命令,可以是字符串或者序列類型(如:list奴烙,元組)
- bufsize:指定緩沖助被。0 無緩沖,1 行緩沖,其他 緩沖區(qū)大小,負(fù)值 系統(tǒng)緩沖
- stdin, stdout, stderr:分別表示程序的標(biāo)準(zhǔn)輸入、輸出切诀、錯(cuò)誤句柄
- preexec_fn:只在Unix平臺(tái)下有效揩环,用于指定一個(gè)可執(zhí)行對象(callable object),它將在子進(jìn)程運(yùn)行之前被調(diào)用
- close_sfs:在windows平臺(tái)下幅虑,如果close_fds被設(shè)置為True丰滑,則新創(chuàng)建的子進(jìn)程將不會(huì)繼承父進(jìn)程的輸入、輸出倒庵、錯(cuò)誤管道褒墨。
所以不能將close_fds設(shè)置為True同時(shí)重定向子進(jìn)程的標(biāo)準(zhǔn)輸入炫刷、輸出與錯(cuò)誤(stdin, stdout, stderr)。 - shell:同上
- cwd:用于設(shè)置子進(jìn)程的當(dāng)前目錄
- env:用于指定子進(jìn)程的環(huán)境變量郁妈。如果env = None柬唯,子進(jìn)程的環(huán)境變量將從父進(jìn)程中繼承。
- universal_newlines:不同系統(tǒng)的換行符不同圃庭,True -> 同意使用 \n
- startupinfo與createionflags只在windows下有效
將被傳遞給底層的CreateProcess()函數(shù)锄奢,用于設(shè)置子進(jìn)程的一些屬性,如:主窗口的外觀剧腻,進(jìn)程的優(yōu)先級等等
subprocess實(shí)現(xiàn)sudo 自動(dòng)輸入密碼
import subprocess
def mypass():
mypass = '123' #or get the password from anywhere
return mypass
echo = subprocess.Popen(['echo',mypass()],
stdout=subprocess.PIPE,
)
sudo = subprocess.Popen(['sudo','-S','iptables','-L'],
stdin=echo.stdout,
stdout=subprocess.PIPE,
)
end_of_pipe = sudo.stdout
print "Password ok \n Iptables Chains %s" % end_of_pipe.read()
一拘央、面向?qū)ο?/h3>
1.1 引子
開發(fā)一款叫做<人狗大戰(zhàn)>的游戲,需要至少2個(gè)角色:人书在、狗灰伟,且人和狗都有不同的技能,如人拿棍打狗儒旬, 狗可以咬人栏账,怎么描述這種不同的角色和他們的功能呢?
def person(name, age, sex, job):
data = {
'name': name,
'age': age,
'sex': sex,
'job': job
}
return data
def dog(name, dog_type):
data = {
'name': name,
'type': dog_type
}
return data
上面兩個(gè)方法相當(dāng)于造了兩個(gè)角色模板栈源,游戲開始挡爵,需要成實(shí)際對象,怎么生成呢甚垦?
d1 = dog("李闖", "京巴")
p1 = person("孫海濤", 36, "F", "運(yùn)維")
p2 = person("林海峰", 27, "F", "Teacher")
兩個(gè)角色對象生成了茶鹃,狗和人還有不同的功能怎么實(shí)現(xiàn)呢?
可以每個(gè)功能再寫一個(gè)函數(shù)艰亮,想執(zhí)行哪個(gè)功能闭翩,直接調(diào)用就可以了。
def bark(d):
print("dog %s:wang.wang..wang..." % d['name'])
def walk(p):
print("person %s is walking..." % p['name'])
walk(p1)
bark(d1)
上面的功能實(shí)現(xiàn)的簡直是完美迄埃!
但是仔細(xì)玩耍一會(huì)疗韵,你就不小心干了下面這件事
p1 = person("孫海濤",36,"F","運(yùn)維")
bark(p1) #把人的對象傳給了狗的方法
事實(shí)上并沒出錯(cuò)。但顯然人是不能調(diào)用狗的功能的侄非,如何在代碼級別實(shí)現(xiàn)這個(gè)限制呢蕉汪?
def person(name, age, sex, job):
def walk(p):
print("person %s is walking..." % p['name'])
data = {
'name': name,
'age': age,
'sex': sex,
'job': job,
'walk': walk
}
return data
def dog(name, dog_type):
def bark(d):
print("dog %s:wang.wang..wang..." % d['name'])
data = {
'name': name,
'type': dog_type,
'bark': bark
}
return data
d1 = dog("李闖", "京巴")
p1 = person("孫海濤", 36, "F", "運(yùn)維")
p2 = person("林海峰", 27, "F", "Teacher")
d1['bark'](d1)
p1['walk'](p1)
1.2
剛才只是阻止了兩個(gè)完全不同的角色之間的功能混用。 但有可能同一種角色彩库,只有部分屬性是不同的肤无。
比如cs里有警察和恐怖份子,但因?yàn)槎际侨撕眨詫懸粋€(gè)角色叫person(), 警察和恐怖份子都可以互相射擊宛渐,但警察不可以殺人質(zhì),恐怖分子可以。
這怎么實(shí)現(xiàn)呢窥翩?在殺人質(zhì)的功能里加個(gè)判斷业岁,如果是警察,就不讓殺就ok了寇蚊。
沒錯(cuò)笔时, 這雖然解決了殺人質(zhì)的問題,但其實(shí)警察和恐怖分子的區(qū)別還有很多仗岸,同時(shí)又有很多共性允耿,如果在每個(gè)區(qū)別處都單獨(dú)做判斷,那得累死扒怖。
但如果就直接寫兩個(gè)角色较锡,就代表相同的功能也要重寫了。
二盗痒、面向過程 VS 面向?qū)ο?/h3>
2.1 編程范式
編程:程序員用特定的語法+數(shù)據(jù)結(jié)構(gòu)+算法組成的代碼來告訴計(jì)算機(jī)如何執(zhí)行任務(wù)的過程蚂蕴。
程序:程序員為了得到一個(gè)任務(wù)結(jié)果而編寫的一組指令的集合。
編程范式:實(shí)現(xiàn)一個(gè)任務(wù)的方式有很多種不同的方式俯邓, 對這些不同的編程方式的特點(diǎn)進(jìn)行歸納總結(jié)得出來的編程方式類別骡楼,即為編程范式。
不同的編程范式本質(zhì)上代表對各種類型的任務(wù)稽鞭,采取的不同的解決問題的思路鸟整。
大多數(shù)語言只支持一種編程范式助币,當(dāng)然也有些語言可以同時(shí)支持多種編程范式循未。
兩種最重要的編程范式分別是面向過程編程和面向?qū)ο缶幊?/strong>。
2.2 面向過程編程(Procedural Programming)
Procedural programming uses a list of instructions to tell the computer what to do step-by-step. *
面向過程又被稱為top-down languages, 就是程序從上到下一步步執(zhí)行梦重,一步步從上到下,從頭到尾的解決問題 亮瓷。
基本設(shè)計(jì)思路就是程序一開始是要著手解決一個(gè)大的問題琴拧,然后把一個(gè)大問題分解成很多個(gè)小問題或子過程。
這些子過程在執(zhí)行的過程中再繼續(xù)分解嘱支,直到小問題足夠簡單蚓胸,可以在一個(gè)小步驟范圍內(nèi)解決。
舉個(gè)典型的面向過程的例子數(shù)據(jù)庫備份*除师,分三步:
連接數(shù)據(jù)庫沛膳,備份數(shù)據(jù)庫,測試備份文件可用性汛聚。
def db_conn():
print("connecting db...")
def db_backup(dbname):
print("導(dǎo)出數(shù)據(jù)庫...",dbname)
print("將備份文件打包锹安,移至相應(yīng)目錄...")
def db_backup_test():
print("將備份文件導(dǎo)入測試庫,看導(dǎo)入是否成功")
def main():
db_conn()
db_backup('my_db')
db_backup_test()
if __name__ == '__main__':
main()
這樣做的問題也是顯而易見的,就是如果你要對程序進(jìn)行修改叹哭,對你修改的那部分有依賴的各個(gè)部分你都也要跟著修改.
舉個(gè)例子:如果程序開頭你設(shè)置了一個(gè)變量值為1忍宋, 但如果其它子過程依賴這個(gè)值為1的變量才能正常運(yùn)行,那如果你改了這個(gè)變量风罩,那這個(gè)子過程你也要修改糠排。
假如又有一個(gè)其它子程序依賴這個(gè)子過程,那就會(huì)發(fā)生一連串的影響超升,隨著程序越來越大入宦,這種編程方式的維護(hù)難度會(huì)越來越高。
所以一般認(rèn)為室琢,如果只是寫一些簡單的腳本云石,去做一些一次性任務(wù),用面向過程的方式是極好的研乒。但如果要處理的任務(wù)是復(fù)雜的汹忠,且需要不斷迭代和維護(hù) 的, 那還是用面向?qū)ο笞罘奖恪?/p>
2.3 面向?qū)ο缶幊蹋∣bject-Oriented Programming)
面向?qū)ο蟮膸讉€(gè)核心特性如下
2.3.1 Class 類
一個(gè)類即是對一類擁有相同屬性的對象的抽象雹熬、藍(lán)圖宽菜、原型。在類中定義了這些對象的都具備的屬性(variables(data))竿报、共同的方法铅乡。
類似例子中的模板
2.3.2 Object 對象
一個(gè)對象即是一個(gè)類實(shí)例化后的實(shí)例。一個(gè)類必須經(jīng)過實(shí)例化后方可在程序中調(diào)用烈菌,一個(gè)類可以實(shí)例化多個(gè)對象阵幸,每個(gè)對象亦可以有不同的屬性,就像人類是指所有人芽世,每個(gè)人是指具體的對象挚赊,人與人之前有共性,亦有不同济瓢。
類似例子中的具體的人與狗
2.3.3 Encapsulation 封裝
在類中對數(shù)據(jù)的賦值荠割、內(nèi)部調(diào)用對外部用戶是透明的,這使類變成了一個(gè)膠囊或容器旺矾,里面包含著類的數(shù)據(jù)和方法蔑鹦。
- 防止數(shù)據(jù)被隨意修改。
- 使外部程序不需要關(guān)注對象內(nèi)部的構(gòu)造箕宙,只需要通過此對象對外提供的接口進(jìn)行直接訪問嚎朽。
2.3.4 Inheritance 繼承
一個(gè)類可以派生出子類,在這個(gè)父類里定義的屬性柬帕、方法自動(dòng)被子類繼承哟忍。
- 通過父類 -> 子類的方式以最簡代碼實(shí)現(xiàn)不同角色的共同點(diǎn)和不同點(diǎn)室囊。
2.3.5 Polymorphism 多態(tài)
多態(tài)是面向?qū)ο蟮闹匾匦?簡單點(diǎn)說:“一個(gè)接口,多種實(shí)現(xiàn)”魁索,指一個(gè)基類中派生出了不同的子類融撞,且每個(gè)子類在繼承了同樣的方法名的同時(shí)又對父類的方法做了不同的實(shí)現(xiàn),這就是同一種事物表現(xiàn)出的多種形態(tài)粗蔚。
人類有多個(gè)人種尝偎,不同人種都是用嘴說不同語言。
三鹏控、面向?qū)ο缶幊?Object-Oriented Programming )介紹
無論用什么形式來編程致扯,我們都要明確記住以下原則:
- 寫重復(fù)代碼是非常不好的低級行為
- 你寫的代碼需要經(jīng)常變更
函數(shù)編程與OOP的主要區(qū)別就是OOP可以使程序更加容易擴(kuò)展和易更改。
不考慮語法細(xì)節(jié)当辐,相比靠函數(shù)拼湊出來的寫法抖僵,用面向?qū)ο笾械念悂韺懽钪苯拥母倪M(jìn)有以下2點(diǎn):
- 代碼量少了近一半
- 角色和它所具有的功能可以一目了然看出來
3.1 類的基本定義
class Role(object): #定義一個(gè)類, class是定義類的語法缘揪,Role是類名耍群,(object)是新式類的寫法
def _init__(self,name,role,weapon,life_value=100,money=15000): #初始化函數(shù)
self.name = name
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
上面的__init__()
叫做初始化方法(或構(gòu)造方法), 在類被調(diào)用時(shí)找筝,這個(gè)方法(雖然它是函數(shù)形式蹈垢,但在類中就不叫函數(shù)了,叫方法)會(huì)自動(dòng)執(zhí)行,進(jìn)行一些初始化的動(dòng)作袖裕。
所以這里寫的__init__(self,name,role,weapon,life_value=100,money=15000)
就是要在創(chuàng)建一個(gè)角色時(shí)給它設(shè)置這些屬性曹抬,那么這第一個(gè)參數(shù)self是什么呢?
每當(dāng)初始化一個(gè)角色急鳄,就需要調(diào)用這個(gè)類一次:
r1 = Role('Alex','police','AK47’) # 生成一個(gè)角色 , 會(huì)自動(dòng)把參數(shù)傳給Role下面的__init__(...)方法
r2 = Role('Jack','terrorist','B22’) # 生成一個(gè)角色
上面創(chuàng)建角色時(shí)谤民,我們并沒有給__init__
傳值,程序也沒未報(bào)錯(cuò)疾宏,是因?yàn)檎抛悖愒谡{(diào)用它自己的__init__(…)
時(shí)自己幫你給self
參數(shù)賦值了
r1 = Role('Alex','police','AK47’) # 此時(shí)self 相當(dāng)于 r1 , Role(r1,'Alex','police','AK47’)
r2 = Role('Jack','terrorist','B22’) # 此時(shí)self 相當(dāng)于 r2, Role(r2,'Jack','terrorist','B22’)
執(zhí)行r1 = Role('Alex','police','AK47’)時(shí),python的解釋器其實(shí)干了兩件事:
- 在內(nèi)存中開辟一塊空間指向r1這個(gè)變量名
- 調(diào)用Role這個(gè)類并執(zhí)行其中的
__init__(…)
方法灾锯,相當(dāng)于Role.__init__(r1,'Alex','police',’AK47’)
兢榨。
這么做是為了把'Alex','police',’AK47’這3個(gè)值跟剛開辟的r1關(guān)聯(lián)起來,就可以直接r1.name, r1.weapon 來調(diào)用顺饮。
所以,為實(shí)現(xiàn)這種關(guān)聯(lián)凌那,在調(diào)用init方法時(shí)兼雄,就必須把r1這個(gè)變量也傳進(jìn)去,否則init不知道要把那3個(gè)參數(shù)跟誰關(guān)聯(lián)呀帽蝶。 - 所以這個(gè)
__init__(…)
方法里的self.name = name, self.role = role
等等的意思就是要把這幾個(gè)值 存到r1的內(nèi)存空間里赦肋。
根據(jù)上圖得知,其實(shí)
self
就是實(shí)例本身!你實(shí)例化時(shí)python會(huì)自動(dòng)把這個(gè)實(shí)例本身通過self
參數(shù)傳進(jìn)去佃乘。
總結(jié):
- 上面的這個(gè)
r1 = Role('Alex','police','AK47’)
動(dòng)作囱井,叫做類的“實(shí)例化”, 就是把一個(gè)虛擬的抽象的類趣避,通過這個(gè)動(dòng)作庞呕,變成了一個(gè)具體的對象了, 這個(gè)對象就叫做實(shí)例 - 剛才定義的這個(gè)類體現(xiàn)了面向?qū)ο蟮牡谝粋€(gè)基本特性封裝程帕,其實(shí)就是使用構(gòu)造方法將內(nèi)容封裝到某個(gè)具體對象中住练,然后通過對象直接或者self間接獲取被封裝的內(nèi)容。
3.2
四愁拭、面向?qū)ο蟮奶匦?/h3>
4.1 封裝
封裝是面向?qū)ο蟮奶卣髦唤补洌菍ο蠛皖惛拍畹闹饕匦浴?br> 封裝,也就是把客觀事物封裝成抽象的類岭埠,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作盏混,對不可信的進(jìn)行信息隱藏。
4.1.1 類 --> 實(shí)例化 --> 實(shí)例對象
__init__ # 構(gòu)造函數(shù)
self.name = name # 屬性惜论、成員變量括饶、字段
def sayhi() # 方法、動(dòng)態(tài)屬性
4.1.2 私有屬性:
__private_attr_name = value (只能內(nèi)部訪問)
def get_heart(self): # 對外部提供只讀訪問接口
return self.__heart
r1._Role__heart # 強(qiáng)制訪問私有屬性
4.1.3 公有屬性
在類里定義的屬性来涨,為公有屬性
例子中的nationality
實(shí)例指向公有屬性
4.1.4 析構(gòu)方法
def del(self):
print("del......run......")
4.2 繼承
面向?qū)ο缶幊?(OOP) 語言的一個(gè)主要功能就是“繼承”图焰。
繼承是指:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進(jìn)行擴(kuò)展蹦掐。
通過繼承創(chuàng)建的新類稱為“子類”或“派生類”技羔。
被繼承的類稱為“基類”、“父類”或“超類”卧抗。
繼承的過程藤滥,就是從一般到特殊的過程。
要實(shí)現(xiàn)繼承社裆,可以通過“繼承”(Inheritance)和“組合”(Composition)來實(shí)現(xiàn)拙绊。
在某些 OOP 語言中,一個(gè)子類可以繼承多個(gè)基類泳秀。但是一般情況下标沪,一個(gè)子類只能有一個(gè)基類,要實(shí)現(xiàn)多重繼承嗜傅,可以通過多級繼承來實(shí)現(xiàn)金句。
繼承概念的實(shí)現(xiàn)方式主要有2類:實(shí)現(xiàn)繼承、接口繼承吕嘀。
? 實(shí)現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力违寞;
? 接口繼承是指僅使用屬性和方法的名稱贞瞒、但是子類必須提供實(shí)現(xiàn)的能力(子類重構(gòu)爹類方法);
在考慮使用繼承時(shí)趁曼,有一點(diǎn)需要注意军浆,那就是兩個(gè)類之間的關(guān)系應(yīng)該是“屬于”關(guān)系。例如挡闰,Employee 是一個(gè)人乒融,Manager 也是一個(gè)人,因此這兩個(gè)類都可以繼承 Person 類尿这。但是 Leg 類卻不能繼承 Person 類簇抵,因?yàn)橥炔⒉皇且粋€(gè)人。
抽象類僅定義將由子類創(chuàng)建的一般屬性和方法射众。
OO開發(fā)范式大致為:劃分對象→抽象類→將類組織成為層次化結(jié)構(gòu)(繼承和合成) →用類與實(shí)例進(jìn)行設(shè)計(jì)和實(shí)現(xiàn)幾個(gè)階段碟摆。
4.2.1 繼承示例
class SchoolMember(object):
"""學(xué)校成員基類"""
member = 0
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
self.enroll()
def enroll(self):
"""注冊"""
print("A new school member [%s] has been enrolled" % self.name)
SchoolMember.member += 1
def tell(self):
print("-----%s info-----" % self.name)
for k, v in self.__dict__.items():
print('\t', k, ':', v)
def __del__(self):
print("%s has been kicked off" % self.name)
SchoolMember.member -= 1
class School(object):
def branch(self, address):
self.address = address
print("Openning a new branch school in %s" % self.address)
class Teacher(SchoolMember, School): # 多繼承
"""講師類"""
def __init__(self, name, age, sex, salary, course):
# SchoolMember.__init__(self, name, age, sex) # 經(jīng)典類寫法
super(Teacher, self).__init__(name, age, sex) # 新式類寫法
self.salary = salary
self.course = course
def teach(self):
print("Teacher [%s] is teaching [%s]" % (self.name, self.course))
class Student(SchoolMember):
def __init__(self, name, age, sex, tuition, course):
SchoolMember.__init__(self, name, age, sex)
self.tuition = tuition
self.course = course
self.amount = 0
def pay_tuition(self, amount):
print("student [%s] has paid [%s]" % (self.name, amount))
self.amount += amount
t1 = Teacher('Alex', 32, 'Male', 1000000, 'Python')
s1 = Student('Will', 32, 'Male', 7000, 'PY_Net')
s2 = Student('Simth', 22, 'Male', 11000, 'PY_S14')
print(SchoolMember.member)
del s2
print(SchoolMember.member)
t1.tell()
s1.tell()
t1.branch("Shanghai")
4.2.2 經(jīng)典類 vs 新式類
- 寫法
class Person(object): # new style
super(Person, self).()
class Person: # classical style
Person.init() - 多繼承時(shí),繼承順序的區(qū)別
廣度查詢叨橱、深度查詢
Python2 中經(jīng)典類為深度查詢典蜕,新式類為廣度查詢
Python3 中經(jīng)典類和新式類均為廣度查詢
4.3 多態(tài)
多態(tài)是為了實(shí)現(xiàn)接口重用。
多態(tài)的作用罗洗,就是為了類在繼承和派生的時(shí)候愉舔,保證使用“家譜”中任一類的實(shí)例的某一屬性時(shí)的正確調(diào)用。
Pyhon不直接支持多態(tài)伙菜,但可以間接實(shí)現(xiàn)轩缤。
通過Python模擬的多態(tài)
class Animal:
def __init__(self, name): # Constructor of the class
self.name = name
def talk(self): # Abstract method, defined by convention only
raise NotImplementedError("Subclass must implement abstract method")
class Cat(Animal):
def talk(self):
return 'Meow!'
class Dog(Animal):
def talk(self):
return 'Woof! Woof!'
animals = [Cat('Missy'),
Dog('Lassie')]
for animal in animals:
print(animal.name + ': ' + animal.talk())
五、補(bǔ)充
5.1 什么是面向?qū)ο缶幊?/h4>
- 之前使用的是函數(shù)式編程
- 現(xiàn)在是類 + 對象
5.2 什么是類贩绕,什么是對象火的?又有什么關(guān)系?
class 類:
def 函數(shù)1():
pass
def 函數(shù)2():
pass
# obj是對象淑倾,實(shí)例化的過程
obj = 類()
obj.函數(shù)1()
class 類:
def 函數(shù)1():
pass
def 函數(shù)2():
pass
# obj是對象淑倾,實(shí)例化的過程
obj = 類()
obj.函數(shù)1()
乍看之下馏鹤,面向?qū)ο蟛缓茫瘮?shù)編程好
有時(shí)候娇哆,函數(shù)編程能實(shí)現(xiàn)功能湃累,但是麻煩;而面向?qū)ο蠓浅:唵蔚木湍軐?shí)現(xiàn)碍讨。
5.3 什么時(shí)候適用面向?qū)ο螅?/h4>
- 根據(jù)一個(gè)模板創(chuàng)建某些東西時(shí)
- 如果多個(gè)函數(shù)需要傳入多個(gè)共同參數(shù)時(shí)
- 應(yīng)用場景
class SSH:
def __init__(self, host, port, username, passwd):
self.host = host
...
def connection(self):
# 去創(chuàng)建連接
self.conn = 和服務(wù)器創(chuàng)建的連接對象()
def close(self):
# 關(guān)閉
self.conn.close
def upload(self):
self.conn 使用連接上傳文件
def cmd(self):
self.conn 使用連接執(zhí)行命令
obj = SHH(......)
obj.connection()
obj.upload()
obj.close()
obj = SHH(......)
obj.connection()
obj.cmd()
obj.upload()
obj.cmd()
obj.close()
5.4 self就是調(diào)用當(dāng)前方法的對象
class Foo:
# 靜態(tài)字段 使用場景為:每個(gè)對象中保存相同的屬性時(shí)治力。
# 公有屬性
country = '中國'
def __init__(self, name, amount):
# 普通字段
# 普通屬性
self.NAME = name
self.AMOUNT = amout
def bar(self):
pass
obj1 = Foo('Alex', 100000)
obj1.bar()
obj2 = Foo('Eric', 10000)
obj2.bar()
5.5
class SSH:
def __init__(self, host, port, username, passwd):
self.host = host
...
def connection(self):
# 去創(chuàng)建連接
self.conn = 和服務(wù)器創(chuàng)建的連接對象()
def close(self):
# 關(guān)閉
self.conn.close
def upload(self):
self.conn 使用連接上傳文件
def cmd(self):
self.conn 使用連接執(zhí)行命令
obj = SHH(......)
obj.connection()
obj.upload()
obj.close()
obj = SHH(......)
obj.connection()
obj.cmd()
obj.upload()
obj.cmd()
obj.close()
class Foo:
# 靜態(tài)字段 使用場景為:每個(gè)對象中保存相同的屬性時(shí)治力。
# 公有屬性
country = '中國'
def __init__(self, name, amount):
# 普通字段
# 普通屬性
self.NAME = name
self.AMOUNT = amout
def bar(self):
pass
obj1 = Foo('Alex', 100000)
obj1.bar()
obj2 = Foo('Eric', 10000)
obj2.bar()
封裝:
類中封裝了字段、方法
對象中封裝了普通字段的值
class F1:
def __init__(self, n):
self.N = n
print('F1')
class F2:
def __init__(self, arg1):
self.a =arg1
print('F2')
class F3:
def __init__(self, arg2):
self.b =arg2
print('F3')
o1 = F1('Alex')
o2 = F2(o1)
o3 = F3(o2)
###### Print Alex ######
# o3 = F3(o2)
o3.b => o2
# o2 = F2(o1)
o3.b.a => o1
# o2 = F1('Alex')
o3.b.a.N
繼承:
class F1(object):
def __init__(self):
print('F1')
def a1(self):
print("F1a1")
def a2(self):
print("F1a2")
class F2(F1):
def __init__(self):
print('F2')
def a1(self):
self.a2()
print("F2a1")
def a2(self):
print("F2a2")
class F3(F2):
def __init__(self):
print('F3')
def a2(self):
print("F3a2")
obj1 = F3()
obj1.a1()
# F3a2
# F2a1
5.6
字段:
- 普通字段(保存在對象中)
- 靜態(tài)字段(保存在類中)
方法:
- 普通方法(保存在類中垄开,調(diào)用者為對象琴许,至少有一個(gè)
self
參數(shù))
class F1:
def __init__(self, name,......)
self.name = name
...
def a1(self):
print(self,name,......)
obj = F1('Alex')
obj,a1()
class F1:
def a1(self):
print('Alex')
obj = F1()
obj.a1()
- 靜態(tài)方法(保存在類中,調(diào)用者為類溉躲,無需創(chuàng)建對象榜田,可以有任意個(gè)參數(shù))
class F1:
@staticmethod
def a1(self):
print('Alex')
F1.a1()
六、作業(yè):選課系統(tǒng)
角色:學(xué)校锻梳、學(xué)員箭券、課程、講師
要求:
- 創(chuàng)建北京疑枯、上海 2 所學(xué)校
- 創(chuàng)建linux , python , go 3個(gè)課程 辩块, linux\py 在北京開, go 在上海開
- 課程包含荆永,周期废亭,價(jià)格,通過學(xué)校創(chuàng)建課程
- 通過學(xué)校創(chuàng)建班級具钥, 班級關(guān)聯(lián)課程豆村、講師
- 創(chuàng)建學(xué)員時(shí),選擇學(xué)校骂删,關(guān)聯(lián)班級
- 創(chuàng)建講師角色時(shí)要關(guān)聯(lián)學(xué)校掌动,
- 提供兩個(gè)角色接口
6.1 學(xué)員視圖, 可以注冊宁玫, 交學(xué)費(fèi)粗恢, 選擇班級,
6.2 講師視圖欧瘪, 講師可管理自己的班級眷射, 上課時(shí)選擇班級, 查看班級學(xué)員列表 佛掖, 修改所管理的學(xué)員的成績
6.3 管理視圖妖碉,創(chuàng)建講師, 創(chuàng)建班級苦囱,創(chuàng)建課程 - 上面的操作產(chǎn)生的數(shù)據(jù)都通過pickle序列化保存到文件里