首先說說反射是什么?反射是可以以字符串的形式動態(tài)調(diào)用函數(shù)的過程。
當(dāng)然反射不只是字符串的函數(shù)執(zhí)行,她和exec和eval不同,反射還可以動態(tài)調(diào)用函數(shù)
eg:如def fun(): print 'a'? 我們調(diào)用的時候應(yīng)該是fun(),如果我們定以一個字符串b =fun,我們在以b()調(diào)用函數(shù)則會報錯,所以函數(shù)調(diào)用的時候不能是字符串
但是有時候我們遇到的問題如果能以字符串讀取 并且可以動態(tài)調(diào)用 就會比較方便
eg:我要定義一個網(wǎng)頁的功能,假定下面的這些函數(shù)是在commons模塊里面
def login():
? ? ? print("這是一個登陸頁面!")
def logout():
? ? print("這是一個退出頁面!")
def home():
? ? print("這是網(wǎng)站主頁面!"
這樣我們輸入網(wǎng)址,根據(jù)split分割的網(wǎng)址,如果網(wǎng)址第二項是login就調(diào)用第一個函數(shù),是logout就調(diào)用第二個函數(shù)等等,我們可以使用if
import commons
def run():
? ? ? inp = input("請輸入您想訪問頁面的url: ").strip()
? if inp == "login":
? ? commons.login()
? elif inp == "logout":
? ? commons.logout()
? elif inp == "home":
? ? commons.home()
? else:
? ? print("404")
if __name__ == '__main__':
? run()
但是如果我們的類型有100個甚至1000個的時候呢,這樣如果前面我們還是if...這樣我們要寫100甚至1000個,那如果這個時候我們的函數(shù)可以動態(tài)讀取字符串進行調(diào)用的話,我們是不是可以根據(jù)倒數(shù)第二項返回的字符串立即調(diào)用函數(shù),不用再每個 類型使用一次if,例如:
import commons
def run():
? ? inp = input("請輸入您想訪問頁面的url: ").strip()
? func = getattr(commons,inp)#getattr尋找commons里面的inp函數(shù),把字符串形式變成函數(shù)類型
? func()#函數(shù)執(zhí)行
if __name__ == '__main__':
? run()
這樣是不是簡單明了,直接用一個動態(tài)過程進行了函數(shù)調(diào)用
同時,我們也可以使用_import_動態(tài)調(diào)用模塊,其實本身我們直接用import的 時候,里面本質(zhì)的過程就是_import_(),具體使用過程如下:
def run():
? inp = input("請輸入您想訪問頁面的url: ").strip()
? modules, func = inp.split("/")
? obj = __import__(modules)#查找與字符串相同的模塊
? if hasattr(obj, func):#判斷對象中是否有func,返回bool布爾值
? ? func = getattr(obj, func)
? ? func()
? else:
? ? print("404")
if __name__ == '__main__':
? run()
另外需要 注意:如果存在模塊和真實的函數(shù)調(diào)用存在出入,并且有跡可循,例如全是w.函數(shù)? 這時我們直接用"w."+modules是不可以的,我們必須這樣使用? __import__("lib." + modules, fromlist=True) 必須 加上fromlist參數(shù),不然_import_就只會讀取點號之前的字符串去模塊中進行查找