Python開發基礎----反射、面向對象進階
阿新 • • 發佈:2017-07-18
elf bob 是否 pro sat 自己的 代碼 改變 數據類型
isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)檢查是否obj是否是類 cls 的對象,如果是返回True
1 class Foo(object): 2 pass 3 obj = Foo() 4 print(isinstance(obj, Foo))
issubclass(sub, super)檢查sub類是否是 super 類的派生類,如果是返回True
1 class Foo(object): 2 pass 3 class Bar(Foo): 4 pass 5 issubclass(Bar, Foo)
反射
反射主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。
python面向對象中的反射:通過字符串的形式操作對象相關的屬性。而python中的一切事物都是對象,即都可以使用反射。
示例代碼:
1 class Teacher: 2 school=‘jialidun‘ 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 def teach(self): 7 print(‘%s teach‘ %self.name)
通過字符串的方式判斷是否存在一個屬性:
1 t=Teacher(‘bob‘,18) 2 print(hasattr(Teacher,‘name‘)) #False 3 print(hasattr(Teacher,‘school‘)) #True 4 print(hasattr(Teacher,‘teach‘)) #True 5 print(hasattr(t,‘name‘)) #True 6 print(hasattr(t,‘school‘)) #True 7 print(hasattr(t,‘teach‘)) #True
通過字符串的方式獲取一個屬性:
1 print(getattr(Teacher,‘school‘)) #獲取到則返回屬性的值 2 print(getattr(Teacher,‘sdfad‘,None)) #獲取不到返回None,如果不指定None那麽拋出異常錯誤
通過字符串的方式設定一個屬性:
1 setattr(Teacher,‘sex‘,‘male‘) #設定Teacher類的屬性sex=‘male‘ 2 setattr(t,‘sex‘,‘female‘) #設定對象t對象的屬性sex=‘female‘ 3 print(Teacher.__dict__) 4 print(t.__dict__)
通過字符串的方式刪除一個屬性:
1 delattr(Teacher,‘sex‘) 2 delattr(t,‘sex‘)
反射應用場景:用戶交互
1 class Cmd: 2 def __init__(self,name): 3 self.name=name 4 def run(self): 5 while True: 6 cmd=input(‘>>>‘).strip() 7 if not cmd:continue 8 if hasattr(self,cmd): #判斷這個類包含不包含輸入的屬性 9 func=getattr(self,cmd) #如果包含,獲取該屬性 10 func() #執行該屬性(輸入name會拋錯提示字符串不能被調用,因為name是一個數據屬性,而非函數屬性) 11 else: 12 print(‘not valid func‘) 13 def ls(self): 14 print(‘ls function‘) 15 def pwd(self): 16 print(‘pwd function‘) 17 def cat(self): 18 print(‘cat function‘) 19 c=Cmd(‘bob‘) 20 c.run()
反射的好處
實現可插拔機制:可以事先定義好接口,接口只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,即可以事先把主要的邏輯寫好(只定義接口),然後後期再去實現接口的功能
動態導入模塊:基於反射當前模塊成員
__str__方法
改變對象的字符串顯示
1 class Teacher: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 t=Teacher(‘bob‘,18) 6 print(t) 7 輸出結果 8 <__main__.Teacher object at 0x0000020FC4DA9278> 9 10 #########分割線君########### 11 12 class Teacher: 13 def __init__(self,name,age): 14 self.name=name 15 self.age=age 16 def __str__(self): 17 return ‘<name:%s age:%s>‘ % (self.name, self.age) 18 t=Teacher(‘bob‘,18) 19 print(t) #t.__str__() 20 輸出結果:類中的__str__函數的執行結果 21 <name:bob age:18>
__del__方法
在程序執行完了之後會自動執行的內容
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 def __del__(self): 5 print(‘執行__del__‘) 6 ‘‘‘一般用來做一些關於對象執行完了之後剩下的垃圾的清理操作‘‘‘ 7 f=Foo(10) 8 print(‘執行完了‘) 9 10 輸出結果:先執行最後的print,沒有代碼了執行__del__函數 11 執行完了 12 執行__del__
刪除對象後立即執行的內容
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 def __del__(self): 5 print(‘執行__del__‘) 6 ‘‘‘做一些關於對象的清理操作‘‘‘ 7 f=Foo(10) 8 del f #刪除的時候也會執行del內容 9 print(‘執行完了‘) 10 11 輸出結果:刪除了f對象後執行了__del__後才執行最後的print 12 執行__del__ 13 執行完了
item系列
以中括號的方式進行處理類似於:
1 l=[‘a‘,‘b‘,‘c‘] 2 dic={‘a‘:1} 3 print(l[1]) 4 print(dic[‘a‘])
__getitem__、__setitem__、__delitem__
1 class Teacher: 2 def __init__(self,name,age,sex): 3 self.name=name 4 self.age=age 5 self.sex=sex 6 def __getitem__(self, item): #查詢 7 # return getattr(self,item) 8 return self.__dict__[item] 9 def __setitem__(self, key, value): #設置 10 # setattr(self,key,value) 11 self.__dict__[key]=value 12 def __delitem__(self, key): #刪除 13 # delattr(self,key) 14 self.__dict__.pop(key) 15 f=Teacher(‘bob‘,18,‘male‘) 16 print(f.name) #f[‘name‘] 17 print(f[‘name‘]) #查詢 18 f[‘name‘]=‘bob_nb‘ #設置 19 print(f.__dict__) 20 del f[‘name‘] #刪除 21 print(f.__dict__)
__len__方法
給對象提供len()統計方法
1 class Teacher: 2 def __init__(self,name,age,sex): 3 self.name=name 4 self.age=age 5 self.sex=sex 6 def __len__(self): #長度設置為10 7 return 10 8 f=Teacher(‘bob‘,18,‘male‘) 9 print(len(f)) #輸出10
其他方法(補充)
__setattr__,__delattr__,__getattr__方法
1 class Foo: 2 x=1 3 def __init__(self,y): 4 self.y=y 5 def __getattr__(self, item): 6 print(‘----> from getattr:你找的屬性不存在‘) 7 def __setattr__(self, key, value): #限制賦值,無法對屬性直接賦值,必須要對__dict__進行操作賦值 8 print(‘----> from setattr‘) 9 # self.key=value #這就無限遞歸了,任何賦值操作都會調用__setattr__的運行,所以.... 10 # self.__dict__[key]=value #應該使用這種方式,操作字典可以賦值成功 11 def __delattr__(self, item): 12 print(‘----> from delattr‘) 13 # del self.item #無限遞歸了,同__setattr__方法的無限遞歸 14 self.__dict__.pop(item) 15 #__setattr__添加/修改屬性會觸發它的執行 16 f1=Foo(10) 17 f1.__setattr__(‘a‘,1) #不是直接操作字典,無法賦值 18 print(f1.__dict__) # 因為重寫了__setattr__,凡是賦值操作都會觸發它的運行,什麽都不寫,就是根本沒賦值,除非直接操作屬性字典,否則永遠無法賦值 19 f1.z=3 20 print(f1.__dict__) 21 #__delattr__刪除屬性的時候會觸發 22 f1.__dict__[‘a‘]=3#我們可以直接修改屬性字典,來完成添加/修改屬性的操作 23 del f1.a #刪除的時候如果上面函數是del self.item,會無限遞歸 24 print(f1.__dict__) 25 26 #__getattr__只有在使用點調用屬性且屬性不存在的時候才會觸發 27 f1.xxxxxx
包裝(對標準數據類型進行方法修改)
通過繼承和派生的方式,進行修改源生數據類型的方法
1 class List(list): #繼承list所有的屬性,也可以派生出自己新的,比如append和mid 2 def append(self, p_object): 3 ‘派生自己的append:加上類型檢查‘ 4 if not isinstance(p_object,int): 5 raise TypeError(‘must be int‘) 6 super().append(p_object) 7 @property 8 def mid(self): 9 ‘新增自己的屬性‘ 10 index=len(self)//2 11 return self[index]
Python開發基礎----反射、面向對象進階