Day06的課程要點記錄
詳細(xì)教程地址:Day6 - 面向?qū)ο髮W(xué)習(xí)
上節(jié)補遺 - Subprocess
模塊
os.system # 輸出命令結(jié)果到屏幕,返回命令執(zhí)行狀態(tài)
os.popen("dir").read() # 會保存命令的執(zhí)行結(jié)果輸出
subprocess
模塊主要用于替換幾個舊模塊:os.system
, os.spawn*
常用subprocess
方法示例
subprocess.run() # Python 3.5 后才出現(xiàn)的方法
執(zhí)行命令,返回命令執(zhí)行狀態(tài) , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"]) # 命令用列表單個傳入,或者完整輸入字符串,用`shell=True`來執(zhí)行操作系統(tǒng)執(zhí)行。該方法效果類似os.system
#執(zhí)行命令,如果命令結(jié)果為0,就正常返回,否則拋異常
>>> subprocess.check_call(["ls", "-l"])
0
#接收字符串格式命令,返回元組形式,第1個元素是執(zhí)行狀態(tài),第2個是命令結(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() 殺掉所啟動進程
communicate() 等待任務(wù)結(jié)束
stdin 標(biāo)準(zhǔn)輸入
stdout 標(biāo)準(zhǔn)輸出
stderr 標(biāo)準(zhǔn)錯誤
pid
The process ID of the child process.
例子:
stdin
, stdout
等,必須要加參數(shù)subprocess.PIPE
,才能read()
類似操作系統(tǒng)中,不同進程的程序互相傳數(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ù)情況下能滿足需求,但如果你可能需要進行一些復(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)輸入、輸出、錯誤句柄
- preexec_fn:只在Unix平臺下有效,用于指定一個可執(zhí)行對象(callable object),它將在子進程運行之前被調(diào)用
- close_sfs:在windows平臺下,如果close_fds被設(shè)置為True,則新創(chuàng)建的子進程將不會繼承父進程的輸入、輸出、錯誤管道。
所以不能將close_fds設(shè)置為True同時重定向子進程的標(biāo)準(zhǔn)輸入、輸出與錯誤(stdin, stdout, stderr)。 - shell:同上
- cwd:用于設(shè)置子進程的當(dāng)前目錄
- env:用于指定子進程的環(huán)境變量。如果env = None,子進程的環(huán)境變量將從父進程中繼承。
- universal_newlines:不同系統(tǒng)的換行符不同,True -> 同意使用 \n
- startupinfo與createionflags只在windows下有效
將被傳遞給底層的CreateProcess()函數(shù),用于設(shè)置子進程的一些屬性,如:主窗口的外觀,進程的優(yōu)先級等等
subprocess實現(xiàn)sudo 自動輸入密碼
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個角色:人、狗,且人和狗都有不同的技能,如人拿棍打狗, 狗可以咬人,怎么描述這種不同的角色和他們的功能呢?
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
上面兩個方法相當(dāng)于造了兩個角色模板,游戲開始,需要成實際對象,怎么生成呢?
d1 = dog("李闖", "京巴")
p1 = person("孫海濤", 36, "F", "運維")
p2 = person("林海峰", 27, "F", "Teacher")
兩個角色對象生成了,狗和人還有不同的功能怎么實現(xiàn)呢?
可以每個功能再寫一個函數(shù),想執(zhí)行哪個功能,直接調(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)
上面的功能實現(xiàn)的簡直是完美!
但是仔細(xì)玩耍一會,你就不小心干了下面這件事
p1 = person("孫海濤",36,"F","運維")
bark(p1) #把人的對象傳給了狗的方法
事實上并沒出錯。但顯然人是不能調(diào)用狗的功能的,如何在代碼級別實現(xiàn)這個限制呢?
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", "運維")
p2 = person("林海峰", 27, "F", "Teacher")
d1['bark'](d1)
p1['walk'](p1)
1.2
剛才只是阻止了兩個完全不同的角色之間的功能混用。 但有可能同一種角色,只有部分屬性是不同的。
比如cs里有警察和恐怖份子,但因為都是人,所以寫一個角色叫person(), 警察和恐怖份子都可以互相射擊,但警察不可以殺人質(zhì),恐怖分子可以。
這怎么實現(xiàn)呢?在殺人質(zhì)的功能里加個判斷,如果是警察,就不讓殺就ok了。
沒錯, 這雖然解決了殺人質(zhì)的問題,但其實警察和恐怖分子的區(qū)別還有很多,同時又有很多共性,如果在每個區(qū)別處都單獨做判斷,那得累死。
但如果就直接寫兩個角色,就代表相同的功能也要重寫了。
二、面向過程 VS 面向?qū)ο?/h3>
2.1 編程范式
編程:程序員用特定的語法+數(shù)據(jù)結(jié)構(gòu)+算法組成的代碼來告訴計算機如何執(zhí)行任務(wù)的過程。
程序:程序員為了得到一個任務(wù)結(jié)果而編寫的一組指令的集合。
編程范式:實現(xiàn)一個任務(wù)的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結(jié)得出來的編程方式類別,即為編程范式。
不同的編程范式本質(zhì)上代表對各種類型的任務(wù),采取的不同的解決問題的思路。
大多數(shù)語言只支持一種編程范式,當(dāng)然也有些語言可以同時支持多種編程范式。
兩種最重要的編程范式分別是面向過程編程和面向?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è)計思路就是程序一開始是要著手解決一個大的問題,然后把一個大問題分解成很多個小問題或子過程。
這些子過程在執(zhí)行的過程中再繼續(xù)分解,直到小問題足夠簡單,可以在一個小步驟范圍內(nèi)解決。
舉個典型的面向過程的例子數(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()
這樣做的問題也是顯而易見的,就是如果你要對程序進行修改,對你修改的那部分有依賴的各個部分你都也要跟著修改.
舉個例子:如果程序開頭你設(shè)置了一個變量值為1, 但如果其它子過程依賴這個值為1的變量才能正常運行,那如果你改了這個變量,那這個子過程你也要修改。
假如又有一個其它子程序依賴這個子過程,那就會發(fā)生一連串的影響,隨著程序越來越大,這種編程方式的維護難度會越來越高。
所以一般認(rèn)為,如果只是寫一些簡單的腳本,去做一些一次性任務(wù),用面向過程的方式是極好的。但如果要處理的任務(wù)是復(fù)雜的,且需要不斷迭代和維護 的, 那還是用面向?qū)ο笞罘奖恪?/p>
2.3 面向?qū)ο缶幊蹋∣bject-Oriented Programming)
面向?qū)ο蟮膸讉€核心特性如下
2.3.1 Class 類
一個類即是對一類擁有相同屬性的對象的抽象、藍圖、原型。在類中定義了這些對象的都具備的屬性(variables(data))、共同的方法。
類似例子中的模板
2.3.2 Object 對象
一個對象即是一個類實例化后的實例。一個類必須經(jīng)過實例化后方可在程序中調(diào)用,一個類可以實例化多個對象,每個對象亦可以有不同的屬性,就像人類是指所有人,每個人是指具體的對象,人與人之前有共性,亦有不同。
類似例子中的具體的人與狗
2.3.3 Encapsulation 封裝
在類中對數(shù)據(jù)的賦值、內(nèi)部調(diào)用對外部用戶是透明的,這使類變成了一個膠囊或容器,里面包含著類的數(shù)據(jù)和方法。
- 防止數(shù)據(jù)被隨意修改。
- 使外部程序不需要關(guān)注對象內(nèi)部的構(gòu)造,只需要通過此對象對外提供的接口進行直接訪問。
2.3.4 Inheritance 繼承
一個類可以派生出子類,在這個父類里定義的屬性、方法自動被子類繼承。
- 通過父類 -> 子類的方式以最簡代碼實現(xiàn)不同角色的共同點和不同點。
2.3.5 Polymorphism 多態(tài)
多態(tài)是面向?qū)ο蟮闹匾匦?簡單點說:“一個接口,多種實現(xiàn)”,指一個基類中派生出了不同的子類,且每個子類在繼承了同樣的方法名的同時又對父類的方法做了不同的實現(xiàn),這就是同一種事物表現(xiàn)出的多種形態(tài)。
人類有多個人種,不同人種都是用嘴說不同語言。
三、面向?qū)ο缶幊?Object-Oriented Programming )介紹
無論用什么形式來編程,我們都要明確記住以下原則:
- 寫重復(fù)代碼是非常不好的低級行為
- 你寫的代碼需要經(jīng)常變更
函數(shù)編程與OOP的主要區(qū)別就是OOP可以使程序更加容易擴展和易更改。
不考慮語法細(xì)節(jié),相比靠函數(shù)拼湊出來的寫法,用面向?qū)ο笾械念悂韺懽钪苯拥母倪M有以下2點:
- 代碼量少了近一半
- 角色和它所具有的功能可以一目了然看出來
3.1 類的基本定義
class Role(object): #定義一個類, 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ù)形式,但在類中就不叫函數(shù)了,叫方法)會自動執(zhí)行,進行一些初始化的動作。
所以這里寫的__init__(self,name,role,weapon,life_value=100,money=15000)
就是要在創(chuàng)建一個角色時給它設(shè)置這些屬性,那么這第一個參數(shù)self是什么呢?
每當(dāng)初始化一個角色,就需要調(diào)用這個類一次:
r1 = Role('Alex','police','AK47’) # 生成一個角色 , 會自動把參數(shù)傳給Role下面的__init__(...)方法
r2 = Role('Jack','terrorist','B22’) # 生成一個角色
上面創(chuàng)建角色時,我們并沒有給__init__
傳值,程序也沒未報錯,是因為,類在調(diào)用它自己的__init__(…)
時自己幫你給self
參數(shù)賦值了
r1 = Role('Alex','police','AK47’) # 此時self 相當(dāng)于 r1 , Role(r1,'Alex','police','AK47’)
r2 = Role('Jack','terrorist','B22’) # 此時self 相當(dāng)于 r2, Role(r2,'Jack','terrorist','B22’)
執(zhí)行r1 = Role('Alex','police','AK47’)時,python的解釋器其實干了兩件事:
- 在內(nèi)存中開辟一塊空間指向r1這個變量名
- 調(diào)用Role這個類并執(zhí)行其中的
__init__(…)
方法,相當(dāng)于Role.__init__(r1,'Alex','police',’AK47’)
。
這么做是為了把'Alex','police',’AK47’這3個值跟剛開辟的r1關(guān)聯(lián)起來,就可以直接r1.name, r1.weapon 來調(diào)用。
所以,為實現(xiàn)這種關(guān)聯(lián),在調(diào)用init方法時,就必須把r1這個變量也傳進去,否則init不知道要把那3個參數(shù)跟誰關(guān)聯(lián)呀。 - 所以這個
__init__(…)
方法里的self.name = name, self.role = role
等等的意思就是要把這幾個值 存到r1的內(nèi)存空間里。
根據(jù)上圖得知,其實
self
就是實例本身!你實例化時python會自動把這個實例本身通過self
參數(shù)傳進去。
總結(jié):
- 上面的這個
r1 = Role('Alex','police','AK47’)
動作,叫做類的“實例化”, 就是把一個虛擬的抽象的類,通過這個動作,變成了一個具體的對象了, 這個對象就叫做實例 - 剛才定義的這個類體現(xiàn)了面向?qū)ο蟮牡谝粋€基本特性封裝,其實就是使用構(gòu)造方法將內(nèi)容封裝到某個具體對象中,然后通過對象直接或者self間接獲取被封裝的內(nèi)容。
3.2
四、面向?qū)ο蟮奶匦?/h3>
4.1 封裝
封裝是面向?qū)ο蟮奶卣髦唬菍ο蠛皖惛拍畹闹饕匦浴?br> 封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
4.1.1 類 --> 實例化 --> 實例對象
__init__ # 構(gòu)造函數(shù)
self.name = name # 屬性、成員變量、字段
def sayhi() # 方法、動態(tài)屬性
4.1.2 私有屬性:
__private_attr_name = value (只能內(nèi)部訪問)
def get_heart(self): # 對外部提供只讀訪問接口
return self.__heart
r1._Role__heart # 強制訪問私有屬性
4.1.3 公有屬性
在類里定義的屬性,為公有屬性
例子中的nationality
實例指向公有屬性
4.1.4 析構(gòu)方法
def del(self):
print("del......run......")
4.2 繼承
面向?qū)ο缶幊?(OOP) 語言的一個主要功能就是“繼承”。
繼承是指:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。
通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。
被繼承的類稱為“基類”、“父類”或“超類”。
繼承的過程,就是從一般到特殊的過程。
要實現(xiàn)繼承,可以通過“繼承”(Inheritance)和“組合”(Composition)來實現(xiàn)。
在某些 OOP 語言中,一個子類可以繼承多個基類。但是一般情況下,一個子類只能有一個基類,要實現(xiàn)多重繼承,可以通過多級繼承來實現(xiàn)。
繼承概念的實現(xiàn)方式主要有2類:實現(xiàn)繼承、接口繼承。
? 實現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力;
? 接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現(xiàn)的能力(子類重構(gòu)爹類方法);
在考慮使用繼承時,有一點需要注意,那就是兩個類之間的關(guān)系應(yīng)該是“屬于”關(guān)系。例如,Employee 是一個人,Manager 也是一個人,因此這兩個類都可以繼承 Person 類。但是 Leg 類卻不能繼承 Person 類,因為腿并不是一個人。
抽象類僅定義將由子類創(chuàng)建的一般屬性和方法。
OO開發(fā)范式大致為:劃分對象→抽象類→將類組織成為層次化結(jié)構(gòu)(繼承和合成) →用類與實例進行設(shè)計和實現(xiàn)幾個階段。
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() - 多繼承時,繼承順序的區(qū)別
廣度查詢、深度查詢
Python2 中經(jīng)典類為深度查詢,新式類為廣度查詢
Python3 中經(jīng)典類和新式類均為廣度查詢
4.3 多態(tài)
多態(tài)是為了實現(xiàn)接口重用。
多態(tài)的作用,就是為了類在繼承和派生的時候,保證使用“家譜”中任一類的實例的某一屬性時的正確調(diào)用。
Pyhon不直接支持多態(tài),但可以間接實現(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())
五、補充
5.1 什么是面向?qū)ο缶幊?/h4>
- 之前使用的是函數(shù)式編程
- 現(xiàn)在是類 + 對象
5.2 什么是類,什么是對象?又有什么關(guān)系?
class 類:
def 函數(shù)1():
pass
def 函數(shù)2():
pass
# obj是對象,實例化的過程
obj = 類()
obj.函數(shù)1()
class 類:
def 函數(shù)1():
pass
def 函數(shù)2():
pass
# obj是對象,實例化的過程
obj = 類()
obj.函數(shù)1()
乍看之下,面向?qū)ο蟛缓茫瘮?shù)編程好
有時候,函數(shù)編程能實現(xiàn)功能,但是麻煩;而面向?qū)ο蠓浅:唵蔚木湍軐崿F(xiàn)。
5.3 什么時候適用面向?qū)ο螅?/h4>
- 根據(jù)一個模板創(chuàng)建某些東西時
- 如果多個函數(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)字段 使用場景為:每個對象中保存相同的屬性時。
# 公有屬性
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)字段 使用場景為:每個對象中保存相同的屬性時。
# 公有屬性
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)用者為對象,至少有一個
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)建對象,可以有任意個參數(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個課程 , linux\py 在北京開, go 在上海開
- 課程包含,周期,價格,通過學(xué)校創(chuàng)建課程
- 通過學(xué)校創(chuàng)建班級, 班級關(guān)聯(lián)課程、講師
- 創(chuàng)建學(xué)員時,選擇學(xué)校,關(guān)聯(lián)班級
- 創(chuàng)建講師角色時要關(guān)聯(lián)學(xué)校,
- 提供兩個角色接口
6.1 學(xué)員視圖, 可以注冊, 交學(xué)費, 選擇班級,
6.2 講師視圖, 講師可管理自己的班級, 上課時選擇班級, 查看班級學(xué)員列表 , 修改所管理的學(xué)員的成績
6.3 管理視圖,創(chuàng)建講師, 創(chuàng)建班級,創(chuàng)建課程 - 上面的操作產(chǎn)生的數(shù)據(jù)都通過pickle序列化保存到文件里