標籤:read 提示 基類 磁碟 同名 err 調用 school name
類的繼承與派生
經典類和新式類
在python3中,所有類預設繼承object,但凡是繼承了object類的子類,以及該子類的子類,都稱為新式類(在python3中所有的類都是新式類)
沒有繼承object類的子類成為經典類(在python2中,沒有繼承object的類,以及它的子類,都是經典類)
1 class People:2 pass3 class Animal:4 pass5 class Student(People,Animal): #People、Animal稱為基類或父類,Student為子類,Student繼承了People和Animal的所有屬性6 pass7 print(Student.__bases__) #__bases__方法,查看繼承的類的元組8 print(People.__bases__)9 print(Animal.__bases__)
輸出結果:
1 (<class ‘__main__.People‘>, <class ‘__main__.Animal‘>) #繼承了兩個父類2 (<class ‘object‘>,) #預設繼承了object類3 (<class ‘object‘>,)
繼承
繼承是為了減少代碼重用的問題,以減少代碼冗餘。
繼承是一種是什麼是什麼的關係,例如老師類是人類,而非老師類是生日類
繼承類樣本:
1 class People: #定義父類People 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 def walk(self): 6 print(‘%s is walking‘ %self.name) 7 8 #Teacher類和Student類無任何屬性 9 class Teacher(People): #Teacher類繼承People類的屬性10 pass11 class Student(People): #Student類繼承People類的屬性12 pass
引用測試:
1 t=Teacher(‘bob‘,18) #執行個體化一個Teacher對象,而非People對象,Student子類同理 2 print(type(t)) 3 print(t.name,t.age) 4 print(t.__dict__) 5 t.walk() #Teacher子類繼承了People的屬性,使得Teacher子類的對象能夠調用到父類的屬性 6 7 輸出結果: 8 <class ‘__main__.Teacher‘> 9 bob 1810 {‘name‘: ‘bob‘, ‘age‘: 18}11 bob is walking
派生
派生是在子類繼承父類的基礎上, 定義子類專屬的屬性,例如Teacher可以有教師等級的劃分、有教學課程的劃分,但是繼承父類People類是沒有等級和課程的劃分的。
樣本:
1 #定義父類People 2 class People: 3 def __init__(self, name, age,sex): 4 self.name = name 5 self.age = age 6 self.sex=sex 7 def walk(self): 8 print(‘%s is walking‘ % self.name) 9 def test(self):10 print(‘test class from father class %s‘ %self.name)11 #定義Teacher子類12 class Teacher(People):13 school = ‘jialidun‘14 def __init__(self, name, age,sex,level,salary):15 People.__init__(self,name,age,sex) #繼承父類的初始化內容,執行個體化時候接收的參數name、age、sex會傳給People.__init__16 self.level=level #派生的專屬屬性17 self.salary=salary #派生的專屬屬性18 def teach(self): #派生的專屬屬性19 print(‘%s is teaching‘ %self.name)20 def test(self): #派生父類的已有屬性,對象在進行屬性引用的時候會優先引用執行個體化過程中用到的類21 People.test(self)22 print(‘from teacher‘)23 #定義Student子類24 class Student(People):25 def __init__(self, name, age,sex,group):26 People.__init__(self, name, age, sex)27 self.group=group28 def study(self):29 print(‘%s is studying‘ %self.name)
測實驗證:
1 t=Teacher(‘natasha‘,18,‘male‘,10,3000) #__init__(t,‘natasha‘,18,‘male‘,10,3000)2 print(Teacher.__bases__)3 print(Teacher.__dict__)4 t.test()
組合
不同於繼承,組合是包含的意思,表示一種什麼有什麼的關係,也是為了減少重複代碼的
樣本:還是People、Teacher和Student的例子,只是加上了一個Birthday生日類
1 #Birthday類,需要傳入年月日 2 class Birthday: 3 def __init__(self,year,mon,day): 4 self.year=year 5 self.mon=mon 6 self.day=day 7 def tell_birth(self): 8 print(‘出生於<%s>年 <%s>月 <%s>日‘ % (self.year,self.mon,self.day)) 9 #People類,需要接受名字年齡年月日,年月日傳給Birthday類10 class People:11 def __init__(self, name, age, year, mon, day):12 self.name = name13 self.age = age14 #__init__接收的year, mon, day傳給Birthday類15 self.birth = Birthday(year, mon, day) #包含Birthday類,生日不只是人類才有,其他動物也可以有生日,不同於繼承16 def walk(self):17 print(‘%s is walking‘ % self.name)18 #Teacher類19 class Teacher(People):20 def __init__(self, name, age, year, mon, day,level,salary):21 #__init__接收的name, age, year, mon, day傳給People類22 People.__init__(self,name,age,year,mon,day)23 self.level=level24 self.salary=salary25 def teach(self):26 print(‘%s is teaching‘ %self.name)27 #Student類28 class Student(People):29 def __init__(self, name, age, year, mon, day,group):30 People.__init__(self,name,age,year,mon,day)31 self.group=group32 def study(self):33 print(‘%s is studying‘ %self.name)
測實驗證:
1 t=Teacher(‘hurry‘,18,1990,2,33,10,3000) #傳入的值為Teacher類接收的值2 print(t.name,t.age) #對象t的名字和年齡3 print(t.birth) #輸出的是一個類對象,因為父類People定義的birth屬性就是一個類Birthday4 t.birth.tell_birth() #查看對象t所繼承的People類的birth屬性(Birthday類)的tell_birth()屬性5 print(t.birth.year)6 print(t.birth.mon)7 print(t.birth.day)
介面和抽象類別
介面
介面是一組功能的入口,要調用某一組功能,需要通過介面來進行調用,而不需要關注這組功能是如何?的,要的只是結果。
在類裡,介面是提取了一群類共同的函數,可以把介面當做一個函數的集合。
python模仿介面樣本:
1 #模仿Linux內檔案讀寫的介面,Linux不管是文本,還是磁碟還是進程都是通過檔案去實現的,只不過方法不同,但是沒關係 2 class File: #定義一個介面類,提供read和write方法,但是一定是pass沒有處理過程的,因為功能的實現具體靠的是子類 3 def read(self): #定介面函數read 4 pass 5 def write(self): #定義介面函數write 6 pass 7 #定義子類實現讀寫功能 8 #文字檔的讀寫 9 class Txt(File): #文本,具體實現read和write10 def du(self): #注意並不是read11 print(‘文本資料的讀取方法‘)12 def xie(self): #注意並不是write13 print(‘文本資料的寫入方法‘)14 #硬碟資料的讀寫15 class Sata(File): #磁碟,具體實現read和write16 def read(self):17 print(‘硬碟資料的讀取方法‘)18 def write(self):19 print(‘硬碟資料的寫入方法‘)20 #進程資料的讀寫21 class Process(File):22 def read(self):23 print(‘進程資料的讀取方法‘)24 def write(self):25 print(‘進程資料的寫入方法‘)
測實驗證:硬碟和進程一樣,所以製作文本和硬碟的測試即可
硬碟讀寫測試:
1 disk=Sata() #執行個體化一個硬碟讀寫對象2 disk.read() #硬碟讀3 disk.write() #硬碟寫4 5 輸出結果:6 硬碟資料的讀取方法7 硬碟資料的寫入方法
文本讀寫測試:執行後會發現沒有任何輸出,那是因為txt對象實際上訪問的read和write屬性並非子類Txt所提供的屬性,Txt所提供的屬性只是du和xie,但是txt對象有read和write屬性,別忘了Txt類是繼承了父類File的屬性,所以實際上txt對象的read和write屬性是父類File提供的
1 txt=Txt()2 txt.read()3 txt.write()
正確的做法是將Txt類的du和xie方法改成read和write方法,這麼做的意義為歸一化
歸一化,讓使用者無需關心對象的類是什麼,只需要的知道這些對象都具備某些功能就可以了,這極大地降低了使用者的使用難度。
抽象類別
抽象類別的本質上也是類,但是抽象類別只能夠被繼承,不能進行執行個體化,也就是說可以當父類,但是不能產生對象。
抽象類別介於介面和歸一化中間,用於實現介面的歸一化
當子類繼承抽象類別的時候,如果抽象類別定義了抽象方法,那麼子類必須要定義同名的方法。即父類限制:
1、子類必須要有父類的方法
2、子類實現的方法必須跟父類的方法的名字一樣
python的抽象類別通過abc模組實現。
介面歸一化樣本:
1 import abc 2 class File(metaclass=abc.ABCMeta): #metaclass指的是元類,邊會講,現在只需記住這個詞 3 @abc.abstractmethod #抽象方法,即一個裝飾器裝飾read屬性 4 def read(self): 5 pass 6 @abc.abstractmethod #抽象方法,即一個裝飾器裝飾write屬性 7 def write(self): 8 pass 9 # # 當繼承File類時候,如果沒有read和write方法,會提示出錯TypeError: Can‘t instantiate abstract class Txt with abstract methods read, write10 # class Txt(File):11 # def du(self):12 # print(‘文本資料的讀取方法‘)13 # def xie(self):14 # print(‘文本資料的寫入方法‘)15 #定義子類具體實現文本的讀寫操作16 class Txt(File):17 def read(self):18 print(‘文本資料的讀取方法‘)19 def write(self):20 print(‘文本資料的寫入方法‘)21 #定義子類具體實現硬碟的讀寫操作22 class Sata(File):23 def read(self):24 print(‘硬碟資料的讀取方法‘)25 def write(self):26 print(‘硬碟資料的寫入方法‘)27 #定義子類具體實現進程的讀寫操作28 class Process(File):29 def read(self):30 print(‘進程資料的讀取方法‘)31 def write(self):32 print(‘進程資料的寫入方法‘)
測實驗證:
1 t=Txt() 2 t.read() 3 t.write() 4 s=Sata() 5 s.read() 6 s.write() 7 輸出結果: 8 文本資料的讀取方法 9 文本資料的寫入方法10 硬碟資料的讀取方法11 硬碟資料的寫入方法
python基礎之繼承派生、組合、介面和抽象類別