標籤:use 設計 狀態 medium 租房 代碼 format 機制 邏輯
什麼是反射?
反射的概念是由Smith在1982年提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和物件導向方面取得了成就。
四個可以實現自省的函數,是Python的內建函數
# 示範代碼class BlackMedium: feature = ‘Ugly‘ def __init__(self, name, address): self.name = name self.address = address def sell_house(self): print("[%s] 是賣房子的,sb才從它這買" %self.name) def rent_house(self): print("[%s] 是租房子的,sb才從它這租,它黑人" %self.name)# 執行個體化b1 = BlackMedium(‘某某置業‘, ‘回龍觀‘)
- hasattr(object, name):判斷object裡有沒有一個name字串(‘屬性名稱‘)對應的方法或屬性。
object:表示對象; name:屬性名稱,是字串形式;
# 檢測資料屬性print(hasattr(b1, ‘name‘)) # True # b1.__dict__[‘name‘]# 檢測函數屬性print(hasattr(b1, ‘sell_house‘)) # Trueprint(hasattr(b1, ‘sell_housereqre‘)) # False
- getattr(object, name, default=None): 擷取屬性值
object:表示對象; name:屬性名稱,是字串形式;value:屬性對應的值
# 擷取屬性的具體值print(getattr(b1, ‘name‘)) # 某某置業print(getattr(b1, ‘rent_house‘)) # <bound method BlackMedium.rent_house of <__main__.BlackMedium object at 0x00B52F50>>func = getattr(b1, ‘rent_house‘)func() # [某某置業] 是租房子的,sb才從它這租,它黑人print(getattr(b1, ‘feature‘)) # Ugly# default 參數print(getattr(b1, ‘sell_house323‘, ‘沒有這個屬性‘)) # 沒有這個屬性getattr() # 等價於 b1.sell_house
- setattr(object, name, value): 修改或者新增屬性及值
object:表示對象; name:屬性名稱,是字串形式;value:屬性對應的值
# setattr設定資料屬性setattr(b1, ‘sb‘, True)setattr(b1, ‘sb1‘, 1234)setattr(b1, ‘name‘, "萬神置業")setattr(b1, ‘feature‘, ‘黑中介‘)print(b1.__dict__)# {‘name‘: ‘萬神置業‘, ‘address‘: ‘回龍觀‘, ‘sb‘: True, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘}# setattr設定函數屬性setattr(b1, ‘funct‘, lambda x:x+1)setattr(b1, ‘funct1‘, lambda self:self.name+"ss")print(b1.__dict__)# {‘name‘: ‘萬神置業‘, ‘address‘: ‘回龍觀‘, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘, ‘funct‘: <function <lambda> at 0x02FEB618>}# 調用新增的函數屬性print(b1.funct(10)) # 11print(b1.funct1(b1)) # 萬神置業ss
- delattr(object, name) 刪除屬性。
object:表示對象; name:屬性名稱,是字串形式
delattr(b1, ‘sb‘) # 等於 del b1.sbprint(b1.__dict__)# {‘name‘: ‘萬神置業‘, ‘address‘: ‘回龍觀‘, ‘sb1‘: 1234, ‘feature‘: ‘黑中介‘}
-
- 再看這四個方法對類(BlackMedium)的使用
# 定義類,但沒有進行執行個體化class BlackMedium: feture=‘Ugly‘ def __init__(self,name,addr): self.name=name self.addr=addr def sell_hourse(self): print(‘【%s】 正在賣房子,傻逼才買呢‘ %self.name) def rent_hourse(self): print(‘【%s】 正在租房子,傻逼才租呢‘ % self.name)
# hasattr()print(hasattr(BlackMedium,‘feture‘)) # Trueprint(getattr(BlackMedium,‘feture‘))print(setattr(BlackMedium, ‘feture‘, ‘黑中介‘))print(getattr(BlackMedium, ‘feture‘)) # 黑中介delattr(BlackMedium, ‘sell_hourse‘)print(BlackMedium.__dict__)# {‘__module__‘: ‘__main__‘, ‘feture‘: ‘黑中介‘, ‘__init__‘: <function BlackMedium.__init__ at 0x007D1B70>, ‘rent_hourse‘: <function BlackMedium.rent_hourse at 0x007D1AE0>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘BlackMedium‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘BlackMedium‘ objects>, ‘__doc__‘: None}#
二. 為什麼用反射?
是項目中,一個項目有多個程式員寫,如果A寫程式的時候要用到B所寫的類,但是B休假了,還沒有完成他寫的類,A想到了反射,使用了反射機制A可以繼續完成自己的代碼,等B休假回來後再繼續完成類的定義並且實現A想要的功能。
總之,反射好處就是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種“後期綁定”,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能。
示範:
class FtpClient: ‘ftp用戶端,還沒具體實現功能‘ def __init__(self,addr): print("正在串連伺服器[{}]".format(addr)) self.addr = addrf1 = FtpClient(‘192.168.123.123‘)# f1.put() # 因為B還沒定義put()方法,所以會報錯,不能這麼幹,所以需要用下面的判斷做if hasattr(f1,‘put‘): # 判斷f1裡是否有put 方法 func_get = getattr(f1, ‘put‘) # 如果有,就可以get到這個方法 func_get() # 然後運行這個方法else: print("執行其他邏輯") # 如果沒有put這個方法,就執行其他邏輯# 結果正在串連伺服器[192.168.123.123]執行其他邏輯B只定義了介面,還沒實現功能
class FtpClient: ‘ftp用戶端,還沒具體實現功能‘ def __init__(self,addr): print("正在串連伺服器[{}]".format(addr)) self.addr = addr # B休假回來了,實現了put方法 def put(self): print("檔案開始上傳了")# from try import FtpClientf1 = FtpClient(‘192.168.123.123‘)# f1.put()if hasattr(f1,‘put‘): # 判斷f1裡是否有put 方法 func_get = getattr(f1, ‘put‘) # 如果有,就可以get到這個方法 func_get() # 然後運行這個方法else: print("執行其他邏輯") # 如果沒有put這個方法,就執行其他邏輯#結果正在串連伺服器[192.168.123.123]檔案開始上傳了B休假回來,實現了A想要的方法
第三十四篇 Python物件導向之 反射(自省)