Python動態(tài)導(dǎo)入模塊和反射機制詳解
一、前言
何謂動態(tài)導(dǎo)入模塊,就是說模塊的導(dǎo)入可以根據(jù)我們的需求動態(tài)的去導(dǎo)入,不是像一般的在代碼文件開頭固定的導(dǎo)入所需的模塊。
何謂反射機制,利用字符串的形式在模塊或?qū)ο笾胁僮鳎ú檎?獲取/刪除/添加)成員。
下面進入具體實例介紹環(huán)節(jié)。先創(chuàng)建一個示例文件example.py,簡單寫入幾個加減乘除函數(shù),如下,方便下文講解使用。
flag = 1 # 此變量在介紹反射機制時會用到 def my_sum(a, b): return a + b def my_sub(a, b): return a - b
二、動態(tài)導(dǎo)入模塊
一般,如果我們想從其他文件引用上面的幾個函數(shù)方法,都會如下使用:
import example as count # 加法 sum = count.my_sum(2, 3) # 減法 sub = count.my_sub(6, 2) print("sum: {}, sub: {}".format(sum, sub))
但現(xiàn)在有這樣的需求,我需要動態(tài)輸入一個模塊名,可以隨時訪問到導(dǎo)入模塊中的方法或者變量,怎么做呢?看下面。
imp = input("請輸入你需要導(dǎo)入的模塊名稱:") count = __import__(imp) # 這種方式就是通過輸入字符串導(dǎo)入你想導(dǎo)入的模塊 # 加法 sum = count.my_sum(2, 3) # 減法 sub = count.my_sub(6, 2) print("sum: {}, sub: {}".format(sum, sub))
上面實現(xiàn)了動態(tài)輸入模塊名,從而使我們能夠?qū)肽K并且執(zhí)行里面的函數(shù)。但是上面有一個缺點,那就是執(zhí)行的函數(shù)被固定了。那么,我們能不能改進一下,動態(tài)輸入函數(shù)名,并且來執(zhí)行呢?看下面。
imp = input("請輸入你需要導(dǎo)入的模塊名稱:") count = __import__(imp) func = input("請輸入你需要使用的函數(shù)名:") f = getattr(count, func, None) # 加法 sum = f(2, 3) print(sum)
getattr()方法的作用是:從導(dǎo)入的模塊中找到你需要調(diào)用的函數(shù)func,然后返回一個該函數(shù)的引用,沒有找到就煩會None。
這樣我們就實現(xiàn)了,動態(tài)導(dǎo)入一個模塊,并且動態(tài)輸入函數(shù)名然后執(zhí)行相應(yīng)方法。
不過,上面還存在一點點小問題:那就是我們的模塊有可能不是在本級目錄中存放著,有可能是如下圖存放方式:
那怎么辦呢?看下面。
imp = input("請輸入你想導(dǎo)入的模塊名稱:") count = __import__('first_level.{}'.format(imp), fromlist=True) fun = input("請輸入你想要使用的函數(shù)名:") f = getattr(count, fun, None) # 加法 sum = f(2, 3) print(sum)
三、反射機制(又叫 python自省)
我們先來介紹python的四個內(nèi)置函數(shù):
1. getattr()
這個函數(shù)是Python自省的核心函數(shù),具體使用上面已經(jīng)介紹了,她不僅可以用于在模塊中查找獲取相應(yīng)的方法和變量,也可以在一個對象中查找和獲取相應(yīng)的方法和變量,這里就不距離介紹了。
2、hasattr(object, name)
判斷模塊(或?qū)ο髈bject)是否包含名為name的方法或變量(hasattr是通過調(diào)用getattr(ojbect, name)是否拋出異常來實現(xiàn)的)
imp = input("請輸入你想導(dǎo)入的模塊名稱:") count = __import__('first_level.{}'.format(imp), fromlist=True) print(hasattr(count, "my_sum")) # 判斷模塊count中是否存在my_sum方法,存在返回True
3、setattr(object, name, value)
這是相對應(yīng)的getattr()。參數(shù)是一個對象,一個字符串和一個任意值。字符串name可以是對象(object)中一個現(xiàn)有的屬性或一個新的屬性,這個函數(shù)將值(value)賦給屬性(name)的。使用示例,setattr(x, y, v)相當(dāng)于x.y = v。
imp = input("請輸入你想導(dǎo)入的模塊名稱:") count = __import__('first_level.{}'.format(imp), fromlist=True) setattr(count, "flag", 0) # 即使example模塊中沒有flag變量,此處也成立,沒有的話相當(dāng)于給模塊中新增一個變量flag print(count.flag) # 打印出flag的值為0
4、delattr(object, name)
與setattr()相關(guān)的一組函數(shù)。參數(shù)是由一個對象(記住!python中一切皆是對象)和一個字符串(name)組成的。name參數(shù)必須是對象屬性名之一。該函數(shù)刪除該對象的一個由字符串(name)指定的屬性。delattr(x, y)=del x.y.
imp = input("請輸入你想導(dǎo)入的模塊名稱:") count = __import__('first_level.{}'.format(imp), fromlist=True) delattr(count, "flag") print(count.flag) # 此處再打印flag的值將會報錯,因為上一步已經(jīng)將flag屬性刪除了
需要注意的是getattr,hasattr,setattr,delattr函數(shù)對模塊的修改都在內(nèi)存中進行,并不會影響文件中真實內(nèi)容。
5、基于反射機制模擬獲取web框架路由的示例
需求:輸入:www.xxx.com/example/my_sum,返回執(zhí)行my_sum的結(jié)果。
# 動態(tài)導(dǎo)入模塊,并執(zhí)行其中函數(shù) url = input("url: ") target_module = url.split('/')[-2] # 分割url,取出模塊名 module = __import__('first_level.' + target_module, fromlist=True) inp = url.split("/")[-1] # 分割url,并取出url最后一個字符串 if hasattr(module, inp): # 判斷在commons模塊中是否存在inp這個字符串 target_func = getattr(module, inp) # 獲取inp的引用 sum_ = target_func(2, 3) # 執(zhí)行 print(sum_) else: print("404")
更多關(guān)于Python動態(tài)導(dǎo)入模塊和反射機制請查看下面的相關(guān)文章
相關(guān)文章
python3用PIL把圖片轉(zhuǎn)換為RGB圖片的實例
今天小編就為大家分享一篇python3用PIL把圖片轉(zhuǎn)換為RGB圖片的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07使用Python實現(xiàn)ELT統(tǒng)計多個服務(wù)器下所有數(shù)據(jù)表信息
這篇文章主要介紹了使用Python實現(xiàn)ELT統(tǒng)計多個服務(wù)器下所有數(shù)據(jù)表信息,ETL,是英文Extract-Transform-Load的縮寫,用來描述將數(shù)據(jù)從來源端經(jīng)過抽取(extract)、轉(zhuǎn)換(transform)、加載(load)至目的端的過程,需要的朋友可以參考下2023-07-07Python Datetime模塊和Calendar模塊用法實例分析
這篇文章主要介紹了Python Datetime模塊和Calendar模塊用法,結(jié)合實例形式分析了Python日期時間及日歷相關(guān)的Datetime模塊和Calendar模塊原理、用法及操作注意事項,需要的朋友可以參考下2019-04-04