標籤:python 反射 內建函數 getattr 授權 動態載入 模組
首先,我們來看兩個內建函數,isinstance和issubclass,前者是判斷一個對象是不是相應的類型,比如:
obj = ‘python‘print(isinstance(obj,str))
判斷obj是否為字串類型,結果返回True
後者issubclass則判斷一個類是否為另一個的子類,比如:
class A: passclass B(A): passprint(issubclass(B,A))
判斷B是否為A的子類,結果返回True
反射:其實它的核心本質其實就是利用字串的形式去對象(模組)中操作(尋找/擷取/刪除/添加)成員,一種基於字串的事件驅動!
python的四個重要內建函數:getattr、hasattr、delattr和setattr較為全面的實現了基於字串的反射機制。他們都是對記憶體內的模組進行操作,並不會對源檔案進行修改。
import sysclass Commons: @staticmethod def login(): print("登入頁面") @staticmethod def logout(): print("退出頁面") @staticmethod def home(): print("這是網站首頁")this_moudle = sys.modules[__name__]def run(): inp = input("請輸入想訪問頁面的URl:").strip() if hasattr(Commons,inp): func = getattr(Commons,inp,‘沒有這個頁面‘) func() else: print("404!")run()
從上面的例子可以看到hasattr及getattr的用法,另外還有delattr和setattr方法類似
那麼我們為什麼要用反射機制呢?
其好處有:
1、實現可插拔機制(對於代碼來說),可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種‘後期綁定’,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能
2、動態匯入模組(基於反射當前模組成員)
def run(): inp = input("請輸入您想訪問頁面的url: ").strip() modules, func = inp.split("/") obj = __import__(modules) if hasattr(obj, func): func = getattr(obj, func) func() else: print("404") run()
輸入形如:請輸入您想訪問頁面的url: commons/home
執行結果為:這是網站首頁
在這,順便說一下,官方建議用下述的方式進行模組的匯入
import importlibimportlib.import_module(‘需要匯入的庫‘)
接下來我們看看其他幾個python內建的函數__getattr__、__setattr__、__delattr__
class Foo: def __init__(self,name): self.name = name def __setattr__(self, key, value):#添加/修改屬性會觸發它的執行 if isinstance(value,str): self.__dict__[key] = value print("__setattr__") else: raise TypeError("必須為字串") def __getattr__(self, item):#只有在使用點調用屬性且屬性不存在的時候才會觸發 print("getattr--->%s %s"%(item,type(item))) def __delattr__(self, item):#刪除屬性的時候會觸發 self.__dict__.pop(item) print("__delattr__")f = Foo(‘zds‘)print(f.name)f.age = ‘18‘print(f.age)del f.ageprint(f.__dict__)print(f.xxxxx)
封裝與授權
封裝:python為大家提供了標準資料類型,以及豐富的內建方法,其實在很多情境下我們都需要基於標準資料類型來定製我們自己的資料類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識(其他的標準類型均可以通過下面的方式進行二次加工)
授權:授權是封裝的一個特性, 封裝一個類型通常是對已存在的類型的一些定製,這種做法可以建立,修改或刪除原有產品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的預設屬性。
實現授權的關鍵點就是覆蓋__getattr__方法
以下樣本作為練習:
基於授權定製自己的清單類型,要求定製的自己的__init__方法,
定製自己的append:只能向列表加入字串類型的值
定製顯示列表中間那個值的屬性
其餘方法都使用list預設的
class List(list): def __init__(self,obj): super().__init__(obj) def append(self, p_object): if not isinstance(p_object,str): raise TypeError("must be str type") super().append(p_object) @property def mid_value(self): return self[(self.__len__())//2] def __getattr__(self, item): if hasattr(List,item): func = getattr(List,item) return self.func() else: print("沒有這個方法")l = List([1,2,3,4,5,6])l.append(‘7‘)print(l)print(l.mid_value)l.insert(0,9)print(l)
運行結果為:
[1, 2, 3, 4, 5, 6, ‘7‘]
4
[9, 1, 2, 3, 4, 5, 6, ‘7‘]
Python物件導向之反射