subprocess模塊python
ret = os.system("command")linux |
輸出命令的結果,可是隻返回命令的執行狀態,所以ret的值在正常返回爲0,不正常爲非0shell |
|
ret = os.popen("command").read()編程 |
此命令返回命令執行的結果,ret是命令的輸出,可是沒有執行狀態vim |
|
import commandswindows ret = commands.getstatusoutput("command")安全 |
在python 2.7中存在,3.5中已經不存在的模塊,而且在windows下執行會有問題。 |
|
import subprocess |
以列表方式傳入命令的每個參數,例如linux下的命令df -h就寫成subprocess.run(["df","-h"])編碼 可是這種寫法不支持有管線"|"的命令,若是有管線的命令就須要寫爲: subprocess.run("df -h |grep sda1",shell=True),其中shell=True表明前面的字符串將由linux解析 |
|
subprocess.call() |
就是os.system(),只返回程序的執行狀態,不返回結果。一樣若是有管線則應該使用shell=True參數,其實此參數也能夠在無管線的命令中使用 |
|
subprocess.check_call() |
若是命令執行狀態正常就返回0,不然拋異常 |
|
subprocess.getstatusoutput("command") |
以元祖形式返回(命令的執行狀態,命令的結果)和2.7的commands.getstatusoutput()同樣 |
ret=subprocess.getstatusoutput("ipconfig") |
subprocess.getoutput() |
僅獲取命令輸出 |
ret = subporcess.getoutput("ipconfig")和上面的ret[1]同樣 |
subprocess.check_output() |
若是命令正常執行,則返回結果,不然報錯 |
|
subprocess.Popen("command",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
stdout就是一個標準屏幕輸出,stderror是命令執行錯誤時屏幕上顯示的報錯內容,stdin是一個屏幕輸入
subprocess.PIPE參數表明開闢一個管道(內存空間),用來將Popen的命令輸出保存起來
所以當咱們須要打印結果時,則須要到stdout中讀取,見例子,同時由於他能夠將stdout和stderror分別保存在獨立的PIPE中,所以咱們也就能夠分別獲取正確的輸出和錯誤的報錯。
Popen方法是一個底層封裝,上面使用的集中subprocess的方法內部都是封裝的Popen()方法,使用這個方法能夠本身結合處不少新的方法
Popen方法的參數:
shell:讓操做系統自行解析命令,當shell=True時無需像上面同樣輸入,只須要subprocess.Popen("df -h",shell=True,stdout=subprocess.PIPE)便可
cwd:用於設置子進程的當前目錄
env:用於指定子進程的環境變量,若是env = None,子進程的環境變量將從父進程集成
universla_newlines:自動兼容操做系統的換行符,這個設置默認是打開的
|
ret = subprocess.Popen("ipconfig",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(ret.stdout.read())打印命令的輸出 print(ret.stderr.read())打印報錯 |
ret = subprocess.Popen("command",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)
ret.stdout.read() |
ret.stout.read(),從標準輸出中讀取結果 |
|
ret.poll() |
用來檢查命令的執行狀態,由於當咱們使用Popen命令時若是命令須要執行很長時間實際咱們從輸出上是看不到的,命令至關於後臺運行咱們在命令行裏看不到執行進程,而poll()方法實際就是一種能夠由手動發起的檢測,用來檢測當前命令的執行狀態,
若是程序沒有執行完,則返回None 若是執行完畢,則返回程序執行狀態 0爲正常,異常爲非0 |
|
ret.wait() |
wait()方法則是將程序調用到前臺執行,也就是此時什麼也作不了只能等待程序運行結束,運行正常返回0不然返回非0 |
|
ret.terminate() |
終止程序的運行 |
|
ret.communicate() |
在調用Popen後,能夠向stdin(標準屏幕輸入)中輸入內容,以後經過communicate()方法獲得輸入的內容 |
obj = subprocess.Popen("python",shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
obj.stdin.write(b"print(1) \n") obj.stdin.write(b"print(2) \n") obj.stdin.write(b"print(3) \n") obj.stdin.write(b"print(4) \n")
out = obj.communicate() print(out)
輸出:(b'1\r\n2\r\n3\r\n4\r\n', b'') |
Python sudo輸入密碼
在linux中經過一條命令直接sudo 連同輸入密碼帶執行命令的寫法是:
echo "password" | sudo -S yum install vim
其中sudo -S就是屏幕標準輸入stdin,以前的echo "password" 就是向stdin輸入數據
所以當咱們經過python須要執行sudo 命令時就能夠寫爲
subprocess.Popen("echo 'password' | sudo -S yum install vim",shell=True)便可,此處password中須要用單引號以免命令參數的雙引號重複
面向對象
class類
是對一類擁有相同屬性的對象的抽象、藍圖、圓形。在類中定義了這些對象都具有的屬性(varialbes(data))、共同方法
object對象
一個對象是類的實例化後的實例,一個雷必須通過實例化後方可在程序中調用,一個類能夠實例化多個對象,每一個對象亦能夠有不一樣的屬性,就像人類指全部人,每一個人是指具體的對象,人與人之間的共性,亦有不一樣
開發規範:
一、類名首字母大寫
二、函數全小寫
三、不管是類仍是函數,在定義完名稱後第二行開始應該寫註釋
面向對象的特性
Encapsulation 封裝
在類中對數據的賦值、內部調用,對外部用戶是透明的,這使得類變成一個膠囊或者容器,裏面包含着類的屬性,數據和方法。
封裝的做用有2:一、防止數據被隨意修改 二、使外部程序不須要關注對象的內部構造,只須要經過對象對外提供的接口進行直接訪問便可。
Inheritance 繼承
一個類能夠派生出子類,在這個父類裏定義的屬性、方法自動被子類繼承
定義時共性能夠在父類中定義,而子類中是對象的個性,這樣具象化子類便可建立有一個獨立的對象
經過 父類-->子類的方式,以最小代碼量的方式實現不一樣角色的共同點和不一樣點
Polymorphism 多態
一種接口,有不一樣表現形式
類的定義
定義一個簡單的類
class Dog(object): |
# print("hello,i am a dog.") 類和函數同樣直接打印那麼建立對象就會執行,這樣是不對的,所以須要執行應該放到函數中 |
def sayhi(self): |
|
print("hello,i am a dog") |
|
調用類(實例化)
d = Dog() |
# 機遇dog建立一個名叫d的實例 |
d.sayhi() |
# 對象.函數 便可調用 |
可是上面的類有一個問題,沒法區分建立的對象,由於他們都是打印hello i am dog,我並不知道那個對象作的,
所以我須要傳遞一個參數
class Dog(object): |
|
def __init__(self,name): |
|
self.Name = name |
|
def sayhi(self): |
# print("hello,i am a dog,my name is",name) 這樣會報錯,由於name這個變量時在__init__函數中的局部變量,是不能使用到sayhi函數中的 |
print("hello,i am a dog,my name is",self.Name) |
# 這樣是能夠的, |
d = Dog("zhangsan") |
# 此處所傳遞的參數實際是傳遞給__init__(self,name)中的name,而類中的self實際就是對象,也就是Dog(d,"zhangsan"),而對應的在函數內就變成了d.Name="zhangsan",至關於給d這個對象的Name變量賦值爲"zhangsan",因此在後面sayhi方法中咱們須要傳遞的是self.Name,而不是name |
d2 = Dog("lisi") |
|
類中的self |
類是不少函數的組合,可是函數之間不能互相訪問局部變量,所以就須要self來打通各個函數。self就是指代的就是類實例化後的實例。 |
def __init__() |
類中定義的這種函數,就是構造函數或構造方法,也稱爲初始化方法,若是不向類傳遞參數能夠不定義 |
def sayhi() |
類中的其餘方法,就是類的方法,此處指代出了構造函數外的其餘全部類中的方法 |
因此在類中定義的函數應該始終將self做爲第一個參數。
class test(): |
|
def __init__(self,*args,**kwargs): |
# 若是不傳遞參數能夠不定義這個方法 |
def test(self): |
|
self應該使用存在,而這個類的實際形式參數應該寫到其構造函數中 def __init__(self,...):
由於在構造函數中建立了變量(self.Name),並且咱們也能夠在其餘的方法中直接使用self.Name來引用,所以咱們也可使用一樣的方式來更改變量的值
class test(object):
def __init__(self,name)
self.Name = name
def test(self):
self.Name = new_name
類 --> 實例化 --> 實例對象
def __init__(self): 構造函數
self.name = name # 類的屬性,成員變量
def sayhi(self): # 方法,動態屬性
私有屬性:
self.__heart = "Normal" ,使用__定義的屬性是私有屬性,私有屬性沒法被外部訪問
class test(object):
def __init__(self):
self.__name = "test"
此時外部訪問
a = test()
print(a.__name) 這是沒法訪問的
可是能夠被類中定義的其餘方法訪問
self.__heart = "Normal" ,使用__定義的屬性是私有屬性,私有屬性沒法被外部訪問
class test(object):
def __init__(self):
self.__name = "test"
def test(self):
print(self.__name) # 這是在方法中定義的打印,不是外部要求的打印
a = test()
a.test() # 這樣運行到test()方法時定義的print能夠self.__name打印出來
所以若是要在外部獲取私有屬性,則須要在類內部定義一個新的方法將私有屬性返回,
這是一個比較安全的方法,這樣獲得的值是隻讀的
class test(object): |
|
def __init__(self): |
|
self.__name = "test" |
|
def get_name(self): |
|
return self.__name |
|
a = test()
print(a.get_name()) # 這樣就能夠得到__name的值
若是我不考慮安全性,而直接要求訪問類的私有屬性,則按照以下的方法獲取:
對象._類名__私有屬性
例如
a._test__name
公有屬性:
直接定義在類中的屬性是公有屬性,這個屬性能夠被外部直接調用。公有屬性和成員屬性是有差別的(私有屬性也是成員屬性),成員屬性是定義在構造函數中的,而公有屬性是在類下直接定義的。
class test(object): |
|
nationality = "CN" |
# 公有屬性 |
def __init__(self,name,age): |
|
self.name = name |
# 成員屬性 |
self.__age = age |
# 私有屬性 |
類的公有屬性的更改有以下的方法:
一、直接調用類名更高:test.nationality = "US"
二、經過對象調整:
a1 = test("zhangsan",30)
a2 = test("lisi",44)
a1.nationality = "US"
可是若是經過類名調用,則全部實例對象都會被調整。而若是是經過實例對象調整,則只有本對象被調整
這是由於實例對象中的變量實際是類中的參數的引用,所以經過類.變量的調整就會調整全部對象中的公有屬性。
可是一旦經過對象.變量的方式調整了,則會在對象的內存中建立一個開闢一個新的內存地址,建立了一個新的變量,所以這樣就只改變對象的變量。
系統在對變量進行尋址時,首先選擇對象中是否存在這個變量,若是沒有則向類中尋找。
從位置看,類的公有屬性和類的方法是同級的,所以實際上每一個對象在調用類的方法時也並非將類的方法複製到對象內存中,而是調用的類的方法的引用。所以這也是self存在的緣由。由於是引用因此須要區分不一樣的對象,而self實際就是指代的建立的對象,因此類中的每一個方法都必須有self參數
所以類中的方法實際也是公有的,那麼若是我但願方法也是私有的,就須要在外部定義一個方法來替換
class test(object): |
|
nationality = "CN" |
# 公有屬性 |
def __init__(self,name,age): |
|
self.name = name |
# 成員屬性 |
self.__age = age |
# 私有屬性 |
def test(self): |
|
print("123") |
|
|
|
a1 = test() |
|
a2 = test() |
|
a1.test() |
# 輸出123 |
a1.test() |
# 輸出123 |
def test():
print("234")
a1.test = test # 此處不要加括號,由於加了()就是執行函數,不加括號是爲了將函數體賦值
a1.test() # 輸出234
a2.test() # 輸出123
a1.test()變成了私有的
類的析構方法
在類中定義以下方法:
class test(object):
def __del__(self):
print("...")
這個方法就是析構方法,此方法是在對象被刪除時自動執行。
r1 = test()
del r1 # 這行的命令是在內存中將r1和所建立的r1的內存空間的關係移除,此時r1的內容並無被內存回收,在此時會執行析構方法。當內存空間沒有被引用(del r1就是這種狀況),以後這塊內存就會被python的內存回收機制收回。
析構方法的做用是作一些程序的收尾工做,好比當咱們的程序鏈接了不少客戶端,當咱們del這個對象的時候,能夠在__del__這個方法內定義與客戶端斷開鏈接等操做
單繼承
繼承有兩種繼承方法:
一、實現繼承 是指使用父類的屬性和方法二無需額外編碼的能力
二、接口繼承 是指使用父類的屬性和方法的名稱,可是子類必須提供實現的能力(子類重構父類的方法)
在考慮使用繼承時,應注意 父類和子類之間應該是屬於的關係,例如manager能夠繼承person,可是leg不能繼承person。由於manager是一我的擁有人的完整特徵,manager徹底是屬於person。可是leg只是人的一部分他沒有人的特徵(好比人有鼻子眼睛,可是leg沒有)
繼承的寫法
class Person(object): |
|
def talk(self): |
|
print("。。。") |
|
class BlackPerson(Person): |
# 此時就是繼承了Person,括號中的就是父類 |
def walk(self): |
|
print("walking") |
|
|
|
b = BlackPerson() |
|
b.talk() |
# 繼承父類的方法 |
b.walk() |
# 調用子類本身的方法 |
當須要傳遞新的參數時,須要對構造函數先繼承,後重構
class Person(object): |
|
def __init__(self,name,age): |
# 父類傳遞2個參數,name和age |
self.name = name |
|
self.age = age |
|
self.say_hi(self) |
# 能夠在父類的構造函數中調用父類的方法,這樣後續的子類繼承父類構造函數時自動執行這個方法,也能夠在每一個子類中單獨調用 |
def say_hi(self): |
|
pass |
|
class BlackPerson(Person): |
|
def __init__(self,sname,sage,a): |
# 此時須要在子類中新增一個a參數傳入,那麼久須要先繼承父類的構造函數,在重構子類的構造函數,此時定義子類的構造函數的形式參數 |
Person.__init__(self,sname,sage) |
# 繼承父類的構造函數,注意看此處參數的寫法,實際是將子類的參數傳遞給父類的構造函數,因此這裏是調用應該寫實際參數名 |
self.a = a |
# 重構構造函數,定義新的屬性 |
print(self.name,self.age,self.a) |
# 打印屬性,注意看此時全部的參數均可以打印了,可是self.name 和 self.age實際是繼承的父類裏構造函數的調用,因此獲得的結果繼承的部分仍是父類的,而子類的仍是子類的參數 |
self.say_hi() |
# 由於這是繼承了Person的類,因此我在子類的構造函數中就能夠調用父類的方法 |
a = BlackPerson("zhangsan",30,"xx") |
|
由上面的設置能夠看到,不管是如何繼承,由於有了self,而self就是等於對象,因此才能夠直接使用self.變量來調用,可是若是我在父類中定義一個變量,要計算有多少個「對象」(注意不是子類)調用了這個父類。
例如 一個學院成員的父類,一個老師和一個學生的子類分別繼承了學院成員的父類,此時我在學院成員中定義了一個註冊變量,沒增長一個老師或學生這個變量要加1
那麼在學院成員這個變量的定義就不能使用self,而應該是學院成員這個類名,由於若是使用self,只表明對象本身調用的此時,不能表明類被調用的次數
class SchoolMember(object): |
|
member = 0 |
# 定義公有屬性,以便後續累加 |
def __init__(self,name,age,sex): |
|
self.name = name |
|
self.age = age |
|
self.sex = sex |
|
self.enroll() |
# 在父類中調用一個父類的方法,這樣每一個子類都會執行 |
def enroll(self): |
# 註冊流程 |
SchoolMember.member += 1 |
# 此處本意是每次建立對象就要+1,可是若是使用self,則不會加由於self指代的是對象本身,對象自己不會重複調用。是類在重複調用,所以只能使用類.menmber纔會累加,而這種調用方法實際就要求member必須是公有屬性 |
print("number[%s] just enroll a new school membe [%s]".%(SchoolMember.member, self.name)) |
# 此處能夠self.member,也能夠SchoolMember.member,但決不可直接member |
|
|
class Teacher(SchoolMember): |
|
def __init__(self,name,age,sex,salary): |
|
SchoolMember.__init__(self,name,age,sex) |
|
self.salary = salary |
|
|
|
class Student(SchoolMember): |
|
def __init__(self,name,age,sex,fee): |
|
SchoolMember.__init__(self,name,age,sex) |
|
self.fee = fee |
|
|
|
t1 = Teacher("zhangsan",30,"F",3000) |
|
s1 = Student("lisi",26,"F",2000) |
|
self.__dict__ |
# 將對象的屬性做爲列表打印出來,相似: |
下面的例子是一個使用self.__dict__的例子
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def tell(self):
print(self.__dict__) # 在父類中定義打印對象屬性,打印的格式是{'name': 'zhangsan', 'a': 'xx', 'age': 30}
for i,v in self.__dict__.items():
print(i,v) # 使用self.__dict__.items()的方式將key和value變爲元組,而且賦值兩個變量輸出,結果爲name zhangsan\n age 30...
class BlackPerson(Person):
def __init__(self,sname,sage,a):
Person.__init__(self,sname,sage)
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx")
a.tell()
多繼承
多繼承時原則來講繼承的多個類智能有一個有構造函數,不該該出現多個類多個構造函數對應不一樣的屬性的狀況
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def tell(self):
print(self.__dict__)
for i,v in self.__dict__.items():
print(i,v)
class School(object):
def school_addr(self, address):
print("school address is ", address)
class BlackPerson(Person,School): # BlackPerson繼承了2個父類
def __init__(self,sname,sage,a):
# Person.__init__(self,sname,sage)
super(BlackPerson,self).__init__(sname,sage)
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx")
a.tell()
a.school_addr("sh") # 第二個父類的方法自動得到
同時多繼承我也能夠對兩個父類分別繼承屬性
class Person(object):
def __init__(self,name,age): # Person的構造函數
self.name = name
self.age = age
def tell(self):
print(self.__dict__)
for i,v in self.__dict__.items():
print(i,v)
class School(object):
def __init__(self,addr): # School的構造函數,並制定了一個新的屬性
self.addr = addr
def school_addr(self):
print("school address is ", self.addr)
class BlackPerson(Person,School):
def __init__(self,sname,sage,a,addr): # 子類的構造函數
super(BlackPerson,self).__init__(sname,sage) # Person函數繼承構造函數,使用新式類繼承方法
School.__init__(self,addr) # School函數構造函數繼承,使用的是經典類
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx","sh")
a.tell()
a.school_addr() # 調用父類 School的方法
新式類 vs 經典類
子類繼承父類函數並重構構造函數的時候又兩種繼承父類構造函數的方法
class Person: |
# 經典類建立 |
class Person(object): |
# 新式類建立 |
Person.__init__(self,sname,sage) |
# 經典類繼承構造函數 |
super(BlackPerson,self).__init__(sname,sage) |
# 新式類繼承構造函數 |
多繼承時 繼承順序有區別
概念:
廣度查詢:函數在繼承時從左至右繼承,若是父類中都沒有再想父類的父類裏繼承
例如:
祖父: A
父類:B繼承A、C繼承A
子類:D繼承 B和C
此時在調用D時的查詢順序是 B -- C -- A
深度查詢:函數在繼承時首先在從左側開始從父類一直查詢到父類的父類,若是沒有再到第二繼承順序從父類到父類的父類
例如
祖父:A
父類: B繼承A、C繼承A
子類:D繼承 B和C
此時調用D 查詢順序是 B -- A -- C
在Python 3.0之後,不管是新式類仍是經典類,繼承順序都是廣度查詢
在Python2.7之後,經典類是深度查詢,而新式類則是廣度查詢
多態
繼承和封裝的目的是減小代碼的重複性
而多態的目的是接口重用
python不直接支持多態,可是能夠間接實現
實現的方式是在全局下定義一個函數,將對象傳入,由這個函數來調用對應的接口
class Dog(object): |
# 定義類 |
def __init__(self,name): |
|
self.name = name |
|
|
|
def talk(self): |
|
return "wang!" |
|
|
|
class Cat(object): |
# 定義類 |
def __init__(self,name): |
|
self.name = name |
|
|
|
def talk(self): |
|
return "miao!" |
|
|
|
d = Dog("dahuang") |
|
c = Cat("xiaomi") |
|
|
|
def com_talk(obj): |
# 定義一個通用的方法,而後將建立好的對象傳入,而後再調用對象的talk方法 |
print(obj.talk()) |
|
|
|
com_talk(c) |
# 這樣以後調用talk方法時只須要調用函數再將對象傳入便可,一個方法 根據傳入對象的不一樣而有不通的結果 |
com_talk(d) |
|
一、什麼是面向對象編程
二、什麼是類什麼是對象,有什麼關係
三、何時適用面向對象
# 建立鏈接
obj = SSH(....) # 實例化
obj.conn() # 鏈接服務器
obj.upload() # 上傳
obj.close() # 關閉
上面的方法最後實現起來全部的步驟是能夠直接使用隨意組合,不像函數式要爲每種場景定義方法,而且每次都有重複的操做
四、self 公有屬性 普通屬性
self就是調用當前方法的對象
如上圖,內存中會爲類開闢內存空間,在建立對象後對象的內存空間會有一個類對象指針指向他所實例化的類
同時將本身(對象)傳遞給類的self參數。類的方法保存在類的內存中,而類的屬性則會保存在對象的內存中
當有一種情景,我建立了一個省份的類
class province(object):
def __init__(self,name,count):
self.Name = name
self.Count = count
self.country = "中國"
在這種狀況下,我明知每一個省都屬於中國,可是我仍然將country定義爲普通屬性,就會形成這個屬性在每一個對象中保存,無疑會浪費大量的內存空間。
此時我應該將其定義爲類的公有屬性,一旦定義爲公有屬性,則不管建立多少個對象這個屬性都只建立一次,同時該屬性也再也不保存在對象中,而是保存在類的內存中
class province(object):
country = "中國" # 公有屬性
def __init__(self,name,count):
self.Name = name
self.Count = count
若是每個對象都會有共同的值,則這些值應該定義爲公有屬性
五、封裝、繼承
class F1(object):
def __init__(self,name):
self.Name = name
class F2(object):
def __init__(self,obj):
self.a = obj
class F3(object):
def __init__(self,obj):
self.b = obj
o1 = F1("ZS")
o2 = F2(o1)
o3 = F3(o2)
print(o3.b.a.Name)
上面的例子,最終輸出的是是ZS,對象是能夠相互調用的,os.b就是o2,那麼o2.a就是o1,而o1.Name就是ZS,所以我經過o3來調用時就會變成o3.b.a.Name
class F2(object):
def a1(self):
self.a2() # 下面調用的obj是F3()所以當執行F3.a1()時F3沒有會找F2,而這裏至關因而obj.a2(),而obj是F3建立的,所以調用F3的a2輸出F3A2
print("F2A1") # 以後再打印
def a2(self):
print("F2A2")
class F3(F2):
def a2(self):
print("F3A2")
obj = F3()
obj.a1()
六、
屬性
普通屬性(保存在對象中)
公有屬性(保存在類中)
方法
普通方法(保存在類中,調用者是對象,至少有一個self參數)
靜態方法(能夠有任意個參數)
靜態方法的建立
class F1(object):
def a1(self):
print("123")
當建立上面的對象時,由於沒有定義構造函數因此會被提示有問題
此時咱們能夠經過@staticmethod來裝飾這個函數,使這個函數變爲靜態方法。
class F1(object):
@staticmethod # 變爲靜態方法
def a1(): # 靜態方法self就不須要了
print("123")
調用靜態方法無需建立對象,直接經過類調用便可
F1.a1
靜態方法能夠直接調用無需建立的對象,這點很像原來不創建類而直接定義函數的方法
做業:
選課系統
角色:學校、學員、課程、講師
要求:
一、北京、上海兩所學校
二、建立 linux、python go3個課程,linux\py在北京開,go在上海開
三、課程包含,週期、價格,經過學校建立課程
四、經過學校建立班級,班級關聯課程、講師
五、建立學院時,選擇學校,關聯班級
建立講師角色時要關聯學校
六、提供兩個角色接口
學員視圖,能夠註冊,交學費,選擇班級
講師視圖,講師能夠管理本身的班級,上課時選擇班級,查看班級學員列表,修改所管理學員的成績
管理視圖,建立講師,建立班級,建立課程
七、上面的操做產生的數據都經過pickle序列化保存到文件裏