標籤:反射 ... 設定 對象 getattr __del__ nbsp 使用者 property
isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)檢查是否obj是否是類 cls 的對象,如果是返回True
1 class Foo(object):2 pass3 obj = Foo()4 print(isinstance(obj, Foo))
issubclass(sub, super)檢查sub類是否是 super 類的衍生類別,如果是返回True
1 class Foo(object):2 pass 3 class Bar(Foo):4 pass5 issubclass(Bar, Foo)
反射
反射主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。
python物件導向中的反射:通過字串的形式操作對象相關的屬性。而python中的一切事物都是對象,即都可以使用反射。
範例程式碼:
1 class Teacher:2 school=‘jialidun‘3 def __init__(self,name,age):4 self.name=name5 self.age=age6 def teach(self):7 print(‘%s teach‘ %self.name)
通過字串的方式判斷是否存在一個屬性:
1 t=Teacher(‘bob‘,18)2 print(hasattr(Teacher,‘name‘)) #False3 print(hasattr(Teacher,‘school‘)) #True4 print(hasattr(Teacher,‘teach‘)) #True5 print(hasattr(t,‘name‘)) #True6 print(hasattr(t,‘school‘)) #True7 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=name15 self.age=age16 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__後才執行最後的print12 執行__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]=value12 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=name4 self.age=age5 self.sex=sex6 def __len__(self): #長度設定為107 return 108 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=320 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)//211 return self[index]
Python開發基礎----反射、物件導向進階