一、介面思想 建立關聯的橋梁,方便管理代碼 介面思想提現:為類拓展功能 介面類:用來定義功能的類,為繼承它的子類提供功能的。 該類的功能方法一般不需要有實現體,實現體有繼承它的子類自己去實現。 介面類:用來定義功能的類,為繼承它的子類提供功能的。 該類的功能方法一般不需要有實現體,實現體有繼承它的子 ...
一、介面思想
- 建立關聯的橋梁,方便管理代碼
- 介面思想提現:為類拓展功能
- 介面類:用來定義功能的類,為繼承它的子類提供功能的。 該類的功能方法一般不需要有實現體,實現體有繼承它的子類自己去實現。
#提供所有看門應該有的功能 class WatchInterface: def watch_door(self): pass #沒有去繼承PetInterface,WatchInterface的Dog就是普通的Dog類 #但繼承了PetInterface,該Dog就可以作為寵物狗,同理繼承WatchInterface就可以作為看門狗 class Dog(PetIterface,WatchInterface): def jiao(self): pass def chi(self): pass def pao(self): pass #可以作為寵物及看門貓 class Cat(PetIterface,WatchInterface): pass
二、多態(重點)
定義:多態指的是一類事物有多種形態。
動物有多種形態:人,狗,豬
文件有多種形態:文本文件,可執行文件
相當於我們在父類中定義一個統一的多個共同形態的方法,比如人狗豬都能吃跑叫這些方法,我們在父類將其方法進行抽象,即抽象方法,這種方法的實現體是抽象的,也就是說只寫方法函數名,具體代碼塊實現不寫,交由子類重寫具體實現體。
具體實現方法:
- import abc #abstract base class
- class Sup(metaclass=abc.ABCMeta): #Sup為父類
- 將抽離對象加裝飾器@abc.abstractmethod
- 子類對應方法必須重寫,必須有自己的實現體,不然報錯
- 抽象父類中的抽象方法實現體無意義,實現不實現一樣。
- 註意點:有抽象方法的父類不能被實例化
簡言之:我在父類定一些可以抽離的公共方法的模板,你們下麵的子類必須按照子類的這個模板方法去執行,至於具體執行實現體代碼輸出信息你們子類自己根據自己的情況去輸出想要的信息。但是模板必須有樣,做不到我就給你報錯。
看下麵的例子:
import abc class Quan(metaclass=abc.ABCMeta): def __init__(self,name): self.name=name #共有方法,模板來了,小的們,照這個模板去開頭,具體實現體你們去重寫吧,我不管 @abc.abstractmethod def chi(self): pass @abc.abstractmethod def jiao(self): pass class Dog(Quan): def kanmen(self): print(self.name+'看門') def chi(self): # super().chi() print(self.name+'吃狗糧') def jiao(self): print('汪汪汪') class Wolf(Quan): def bulie(self): print(self.name + '捕獵') def chi(self): super().chi() print(self.name + '吃肉') def jiao(self): print('嗷嗷嗷') dog=Dog('來福') wolf=Wolf('常威') dog.jiao() wolf.jiao() dog.chi() wolf.chi()
在面向對象方法中一般是這樣表述多態性:
向不同的對象發送同一條消息(!!!obj.func():是調用了obj的方法func,又稱為向obj發送了一條消息func),不同的對象在接收時會產生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調用函數,不同的行為就是指不同的實現,即執行不同的函數。
比如:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操作,學生執行的是放學操作,雖然二者消息一樣,但是執行的效果不同
總結:多態性的好處:
- 增加了程式的靈活性:以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用
- 增加了程式的可擴展性
三、鴨子類型
如果看起來像、叫聲像而且走起路來像鴨子,那麼它就是鴨子
#二者都像鴨子,二者看起來都像文件,因而就可以當文件一樣去用 class TxtFile: def read(self): pass def write(self): pass class DiskFile: def read(self): pass def write(self): pass
四、反射
反射:通過字元串來反射/映射到對象/類的屬性上
class People: def __init__(self,name,age): self.name=name self.age=age def run(self): print('%s is running'%self.name) obj=People('egon',18) # ------------------------------------------------------------ # hasattr:查看對象中是否有某個屬性(屬性應該為字元串格式的屬性名),有返回True,沒有返回False print(hasattr(obj,'name')) #結果為:True #判斷對象名obj中是否有'name'這個預設屬性,相當於'name' in obj.__dict__ # ------------------------------------------------------------ # getattr:取出對象中某個屬性的值(屬性應該為字元串格式的屬性名),如果沒有該屬性,報錯,可以設置無該屬性時候的返回值 print(getattr(obj,'name')) #結果為:egon #取出對象名obj中屬性'name'的值,相當於obj.__dict__['name'] print(getattr(obj,'xxx','沒有該對象')) #結果為:沒有該對象 #取出對象名obj中屬性'xxx'的值,如果沒有則返回'沒有該對象' # ------------------------------------------------------------ # setattr:將對象中的某個屬性賦予新值(屬性應該為字元串格式的屬性名),如果該屬性無,添加屬性以及值 setattr(obj,'name','EGON') #將原對象中的'name'賦予新值'EGON',相當於obj.__dict__['name']='EGON' setattr(obj,'xxx',1111) #xxx不在原對象名稱空間,則新增屬性xxx並賦予值1111,相當於obj.__dict__['xxx']=1111 print(obj.name) #結果為:EGON print(obj.__dict__) #結果為:{'name':'EGON','age':18,'xxx':1111} # ------------------------------------------------------------ # delattr:刪除對象中的某個屬性(屬性應該為字元串格式的屬性名) delattr(obj,'name') #刪除對象中的某個屬性 print(obj.__dict__) #結果為 :{'age':18} # 註意:以上操作過程,都涉及到對象屬性,傳入參數的屬性應該都為字元串格式,最後將字元串格式的處理結果反射到對象屬性的值上。 # 可以用下麵使用實例來加深反射的意義: import os os.remove print(hasattr(os,'remove')) #結果為True class Ftp: def get(self): print('運行get函數') def put(self): print('運行put函數') def login(self): print('運行login函數') def run(self): while True: cmd=input('>>>>>:').strip() if hasattr(self,cmd): method=getattr(self,cmd) method() else: print('輸入的方法不存在') # obj=Ftp() # obj.run() ''' # 結果: # >>>>>:get # 運行get函數 # >>>>>:put # 運行put函數 # >>>>>:login # 運行login函數 # >>>>>:hah # 輸入的方法不存在 # ..... '''
五、內置方法
''' 1__str__: 在對象被列印時自動觸發,可以用來定義對象被列印時的輸出信息 # 註意:必須返回一個字元串類型的值 class People: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return 'name:%s age:%s'%(self.name,self.age) obj1=People('egon',18) print(obj1) #實際上在執行:print(obj1.__str__()) #結果為:name:egon age:18 obj2=list([1,2,3]) print(obj2) 結果為:[1, 2, 3] ''' # 2__del__: 在對象被刪除時先自動觸發該方法,可以用來回收對象以外其他相關資源,比如系統資源 class Foo: def __init__(self,x,filepath,encoding='utf-8'): self.x=x self.f=open(filepath,'rt',encoding=encoding) def __del__(self): print('runing....') #回收對象關聯的其他資源 self.f.close() obj=Foo(1,'a.txt') # del obj print('=========>') # 3__call__: 在對象被調用時會自動觸發該方法,可以用來??? class Foo: def __init__(self,x,y): self.x=x self.y=y def __call__(self, *args, **kwargs): print(self,args,kwargs) obj=Foo(1,2) obj(1,2,a=3,b=4) #相當於obj.__call__(obj,1,2,a=3,b=4) # 結果為:<__main__.Foo object at 0x000001B6ABA35B00> (1, 2) {'a': 3, 'b': 4}六、異常處理
- 程式運行時的錯誤
- 程式中的異常處理機制:
- 程式中的所有異常都會被處理
- 程式中的所有異常都需要手動處理
- 如果沒有手動處理異常,異常會交給Python解釋器處理
- 處理方式就是列印異常信息,並停止接收器
- 異常的信息的三部分:
- 異常的追蹤信息:提示錯誤位置
- 異常的類型:告知處理異常應該捕獲什麼類型
- 異常的內容:告知錯誤信息
try: #會出現異常的代碼塊 except '異常類型' as '異常別名': #異常處理邏輯 else: #沒有出現異常會執行該分支 finally: #無論是否出現異常都會執行該分支實例:
try: print(adadadadada) except NameError as e: print('異常信息:',e) else: print('被檢測的代碼塊正常') finally: print('異常是否出現都會執行該分支') print('結束') #結果: 異常信息: name 'adadadadada' is not defined 異常是否出現都會執行該分支 結束