python反射機(jī)制

python根據(jù)字符串動態(tài)加載模塊和類

python作為一種動態(tài)解釋型語言,在實現(xiàn)各種框架方面具有很大的靈活性。

最近在研究python web框架,發(fā)現(xiàn)各種框架中需要顯示的定義各種路由和Handler的映射,如果想要實現(xiàn)并維護(hù)復(fù)雜的web應(yīng)用,靈活性非常欠缺。

如果內(nèi)容以“約定即配置”的方式完成handler和路由的映射操作,可以大大增加python web框架的靈活性,此時動態(tài)映射是必不可少的。

在java mvc框架中,可利用反射機(jī)制,實現(xiàn)動態(tài)映射,而python也可以利用本身的特性,實現(xiàn)動態(tài)映射。

1、獲得指定package對象(其實也是module)

為了遍歷此包下的所有module以及module中的controller,以及controller中的function,必須首先獲得指定的package引用,可使用如下方法:

import(name, globals={}, locals={}, fromlist=)加載package,輸入的name為package的名字字符串

controller_package=import('com.project.controller',{},{},["models"])

ps:直接使用import('com.project.controller')是無法加載期望的package的,只會得到頂層的package-‘com’,除非使用如下方法迭代獲得。

def my_import(name):
    mod = __import__(name)
    components = name.split('.') for comp in components[1:]:
        mod = getattr(mod, comp) return mod

官方文檔描述如下

When the <var style="margin: 0px; padding: 0px;">name</var> variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned,not the module named by <var style="margin: 0px; padding: 0px;">name</var>. However, when a non-empty <var style="margin: 0px; padding: 0px;">fromlist</var> argument is given, the module named by <var style="margin: 0px; padding: 0px;">name</var> is returned. This is done for compatibility with the bytecode generated for the different kinds of import statement; when using "<tt class="samp" style="margin: 0px; padding: 0px;">import spam.ham.eggs</tt>", the top-level package <tt class="module" style="margin: 0px; padding: 0px;">spam</tt> must be placed in the importing namespace, but when using "<tt class="samp" style="margin: 0px; padding: 0px;">from spam.ham import eggs</tt>", the spam.hamsubpackage must be used to find the eggs variable. As a workaround for this behavior, use <tt class="function" style="margin: 0px; padding: 0px;">getattr()</tt> to extract the desired components.

2、遍歷指定package下的所有module

為了獲得controller_package下的module,可先使用dir(controller_package)獲得controller_package對象范圍內(nèi)的變量、方法和定義的類型列表。然后通過

for name in dir(controller_package):
  var=getattr(controller_package,name)
  print type(var)

遍歷此package中的所有module,并根據(jù)約定的controller文件命名方式,發(fā)現(xiàn)約定的module,并在module中發(fā)現(xiàn)約定好的class。

如果name代表的變量不是方法或者類,type(var)返回的值為"<type 'module'>"。

3、遍歷指定module中的class

依然使用dir(module)方法,只不過type(var)返回的值為"<type 'classobj'>"。

4、遍歷指定class中的method

依然使用dir(class)方法,只不過type(var)返回的值為"<type 'instancemethod'>"或者<type 'function'>,第一種為對象方法,第二種為類方法。

5、遍歷指定method中的參數(shù)名

使用method的func_code.co_varnames屬性,即可獲得方法的參數(shù)名列表。

以上方法,適合在python web運(yùn)行前,對所有的controller提前進(jìn)行加載,如果需要根據(jù)用戶的請求再動態(tài)發(fā)現(xiàn)controller,依然可以使用上面的方法完成,只是會更加的簡單,需要需找的controller路徑已知,只需遞歸獲得controller的引用即可,再實例化,根據(jù)action名,執(zhí)行執(zhí)行的action。

四個內(nèi)置函數(shù)

1. getattr()函數(shù)是Python自省的核心函數(shù),具體使用大體如下:
class A: 
def __init__(self): 
self.name = 'zhangjing'
self.age='24'
def method(self): 
print"method print"
  
Instance = A() 
print getattr(Instance , 'name, 'not find') #如果Instance 對象中有屬性name則打印self.name的值,否則打印'not find'
print getattr(Instance , 'age', 'not find') #如果Instance 對象中有屬性age則打印self.age的值,否則打印'not find'
print getattr(a, 'method', 'default') #如果有方法method,否則打印其地址,否則打印default 
print getattr(a, 'method', 'default')() #如果有方法method,運(yùn)行函數(shù)并打印None否則打印default 

2. hasattr(object, name)

說明:判斷對象object是否包含名為name的特性(hasattr是通過調(diào)用getattr(ojbect, name)是否拋出異常來實現(xiàn)的)

3. setattr(object, name, value)

這是相對應(yīng)的getattr()。參數(shù)是一個對象,一個字符串和一個任意值。字符串可能會列出一個現(xiàn)有的屬性或一個新的屬性。這個函數(shù)將值賦給屬性的。該對象允許它提供。例如,setattr(x,“foobar”,123)相當(dāng)于x.foobar = 123。

4. delattr(object, name)

與setattr()相關(guān)的一組函數(shù)。參數(shù)是由一個對象(記住python中一切皆是對象)和一個字符串組成的。string參數(shù)必須是對象屬性名之一。該函數(shù)刪除該obj的一個由string指定的屬性。delattr(x, 'foobar')=del x.foobar

我們可以利用上述的四個函數(shù),來對模塊進(jìn)行一系列操作.

r = hasattr(commons,xxx)判斷某個函數(shù)或者變量是否存在
print(r)  

setattr(commons,'age',18)  給commons模塊增加一個全局變量age = 18,創(chuàng)建成功返回none

setattr(config,'age',lambda  a:a+1)  //給模塊添加一個函數(shù)

delattr(commons,'age')//刪除模塊中某個變量或者函數(shù)

實例

基于反射機(jī)制模擬web框架路由

需求:比如我們輸入:www.xxx.com/commons/f1,返回f1的結(jié)果。

# 動態(tài)導(dǎo)入模塊,并執(zhí)行其中函數(shù)
url = input("url: ")

target_module, target_func = url.split('/')
m = __import__('lib.'+target_module, fromlist=True)

inp = url.split("/")[-1]  # 分割url,并取出url最后一個字符串
if hasattr(m,target_func):  # 判斷在commons模塊中是否存在inp這個字符串
    target_func = getattr(m,target_func)  # 獲取inp的引用
    target_func()  # 執(zhí)行
else:
    print("404")
#a.py
    class b(){...}
#c.py
package = __import__('a')
temp_class    = getattr(package,'b')
temp = temp_class() #b()

反射函數(shù)工具

def get_reflex_cls(name):
    '''
    映射函數(shù)
    :param name: 類名
    :return: 類的實例
    '''
    l_name = 'restapi.' + name.lower() + '.services'  # 接口包路徑
    names = l_name.split('.')
    try:
        mod = __import__(l_name)  # 獲取指定路徑package對象,但只會得到最頂層!
        for n in names[1:]:  # 循環(huán)遍歷包路徑
            mod = getattr(mod, n)
        cls = getattr(mod, name.capitalize())  # 獲取指定文件下的類
        clss = cls()  # 創(chuàng)建實例
        return clss
    except Exception as e:
        return False
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 轉(zhuǎn)自:http://www.cnblogs.com/feixuelove1009/p/5576206.html,只...
    think_lonely閱讀 2,576評論 1 2
  • 前言 def s1(): print("s1是這個函數(shù)的名字!") s = "s1" print("%s是個字符串...
    lijun_m閱讀 1,355評論 0 2
  • 不小心都畫成了豁牙子 以后還是要細(xì)心點 不能捉急
    Miao喵了個咪閱讀 74評論 0 0
  • 1. 不曉得是從什么時候開始,情商這個名詞出現(xiàn)在大眾面前。 最初接觸到情商應(yīng)該是讀初二的時候,語文老師每每上課不得...
    阿瓶姑娘閱讀 1,591評論 0 7

友情鏈接更多精彩內(nèi)容