Python動(dòng)態(tài)導(dǎo)入模塊和反射機(jī)制詳解
一、前言
何謂動(dòng)態(tài)導(dǎo)入模塊,就是說(shuō)模塊的導(dǎo)入可以根據(jù)我們的需求動(dòng)態(tài)的去導(dǎo)入,不是像一般的在代碼文件開頭固定的導(dǎo)入所需的模塊。
何謂反射機(jī)制,利用字符串的形式在模塊或?qū)ο笾胁僮鳎ú檎?獲取/刪除/添加)成員。
下面進(jìn)入具體實(shí)例介紹環(huán)節(jié)。先創(chuàng)建一個(gè)示例文件example.py,簡(jiǎn)單寫入幾個(gè)加減乘除函數(shù),如下,方便下文講解使用。
flag = 1 # 此變量在介紹反射機(jī)制時(shí)會(huì)用到 def my_sum(a, b): return a + b def my_sub(a, b): return a - b
二、動(dòng)態(tài)導(dǎo)入模塊
一般,如果我們想從其他文件引用上面的幾個(gè)函數(shù)方法,都會(huì)如下使用:
import example as count
# 加法
sum = count.my_sum(2, 3)
# 減法
sub = count.my_sub(6, 2)
print("sum: {}, sub: {}".format(sum, sub))
但現(xiàn)在有這樣的需求,我需要?jiǎng)討B(tài)輸入一個(gè)模塊名,可以隨時(shí)訪問(wèn)到導(dǎo)入模塊中的方法或者變量,怎么做呢?看下面。
imp = input("請(qǐng)輸入你需要導(dǎo)入的模塊名稱:")
count = __import__(imp) # 這種方式就是通過(guò)輸入字符串導(dǎo)入你想導(dǎo)入的模塊
# 加法
sum = count.my_sum(2, 3)
# 減法
sub = count.my_sub(6, 2)
print("sum: {}, sub: {}".format(sum, sub))
上面實(shí)現(xiàn)了動(dòng)態(tài)輸入模塊名,從而使我們能夠?qū)肽K并且執(zhí)行里面的函數(shù)。但是上面有一個(gè)缺點(diǎn),那就是執(zhí)行的函數(shù)被固定了。那么,我們能不能改進(jìn)一下,動(dòng)態(tài)輸入函數(shù)名,并且來(lái)執(zhí)行呢?看下面。
imp = input("請(qǐng)輸入你需要導(dǎo)入的模塊名稱:")
count = __import__(imp)
func = input("請(qǐng)輸入你需要使用的函數(shù)名:")
f = getattr(count, func, None)
# 加法
sum = f(2, 3)
print(sum)
getattr()方法的作用是:從導(dǎo)入的模塊中找到你需要調(diào)用的函數(shù)func,然后返回一個(gè)該函數(shù)的引用,沒有找到就煩會(huì)None。
這樣我們就實(shí)現(xiàn)了,動(dòng)態(tài)導(dǎo)入一個(gè)模塊,并且動(dòng)態(tài)輸入函數(shù)名然后執(zhí)行相應(yīng)方法。
不過(guò),上面還存在一點(diǎn)點(diǎn)小問(wèn)題:那就是我們的模塊有可能不是在本級(jí)目錄中存放著,有可能是如下圖存放方式:

那怎么辦呢?看下面。
imp = input("請(qǐng)輸入你想導(dǎo)入的模塊名稱:")
count = __import__('first_level.{}'.format(imp), fromlist=True)
fun = input("請(qǐng)輸入你想要使用的函數(shù)名:")
f = getattr(count, fun, None)
# 加法
sum = f(2, 3)
print(sum)
三、反射機(jī)制(又叫 python自?。?/h2>
我們先來(lái)介紹python的四個(gè)內(nèi)置函數(shù):
1. getattr()
這個(gè)函數(shù)是Python自省的核心函數(shù),具體使用上面已經(jīng)介紹了,她不僅可以用于在模塊中查找獲取相應(yīng)的方法和變量,也可以在一個(gè)對(duì)象中查找和獲取相應(yīng)的方法和變量,這里就不距離介紹了。
2、hasattr(object, name)
判斷模塊(或?qū)ο髈bject)是否包含名為name的方法或變量(hasattr是通過(guò)調(diào)用getattr(ojbect, name)是否拋出異常來(lái)實(shí)現(xiàn)的)
imp = input("請(qǐng)輸入你想導(dǎo)入的模塊名稱:")
count = __import__('first_level.{}'.format(imp), fromlist=True)
print(hasattr(count, "my_sum")) # 判斷模塊count中是否存在my_sum方法,存在返回True
3、setattr(object, name, value)
這是相對(duì)應(yīng)的getattr()。參數(shù)是一個(gè)對(duì)象,一個(gè)字符串和一個(gè)任意值。字符串name可以是對(duì)象(object)中一個(gè)現(xiàn)有的屬性或一個(gè)新的屬性,這個(gè)函數(shù)將值(value)賦給屬性(name)的。使用示例,setattr(x, y, v)相當(dāng)于x.y = v。
imp = input("請(qǐng)輸入你想導(dǎo)入的模塊名稱:")
count = __import__('first_level.{}'.format(imp), fromlist=True)
setattr(count, "flag", 0) # 即使example模塊中沒有flag變量,此處也成立,沒有的話相當(dāng)于給模塊中新增一個(gè)變量flag
print(count.flag) # 打印出flag的值為0
4、delattr(object, name)
與setattr()相關(guān)的一組函數(shù)。參數(shù)是由一個(gè)對(duì)象(記??!python中一切皆是對(duì)象)和一個(gè)字符串(name)組成的。name參數(shù)必須是對(duì)象屬性名之一。該函數(shù)刪除該對(duì)象的一個(gè)由字符串(name)指定的屬性。delattr(x, y)=del x.y.
imp = input("請(qǐng)輸入你想導(dǎo)入的模塊名稱:")
count = __import__('first_level.{}'.format(imp), fromlist=True)
delattr(count, "flag")
print(count.flag) # 此處再打印flag的值將會(huì)報(bào)錯(cuò),因?yàn)樯弦徊揭呀?jīng)將flag屬性刪除了
需要注意的是getattr,hasattr,setattr,delattr函數(shù)對(duì)模塊的修改都在內(nèi)存中進(jìn)行,并不會(huì)影響文件中真實(shí)內(nèi)容。
5、基于反射機(jī)制模擬獲取web框架路由的示例
需求:輸入:www.xxx.com/example/my_sum,返回執(zhí)行my_sum的結(jié)果。
# 動(dòng)態(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最后一個(gè)字符串
if hasattr(module, inp): # 判斷在commons模塊中是否存在inp這個(gè)字符串
target_func = getattr(module, inp) # 獲取inp的引用
sum_ = target_func(2, 3) # 執(zhí)行
print(sum_)
else:
print("404")
更多關(guān)于Python動(dòng)態(tài)導(dǎo)入模塊和反射機(jī)制請(qǐng)查看下面的相關(guān)文章
- python?動(dòng)態(tài)導(dǎo)入模塊實(shí)現(xiàn)模塊熱更新的方法
- Python importlib動(dòng)態(tài)導(dǎo)入模塊實(shí)現(xiàn)代碼
- Python動(dòng)態(tài)導(dǎo)入模塊:__import__、importlib、動(dòng)態(tài)導(dǎo)入的使用場(chǎng)景實(shí)例分析
- Python 動(dòng)態(tài)導(dǎo)入對(duì)象,importlib.import_module()的使用方法
- Python動(dòng)態(tài)導(dǎo)入模塊的方法實(shí)例分析
- Python 靜態(tài)導(dǎo)入與動(dòng)態(tài)導(dǎo)入的實(shí)現(xiàn)示例
相關(guān)文章
Python實(shí)現(xiàn)自定義異常堆棧信息的示例代碼
當(dāng)我們的程序報(bào)錯(cuò)時(shí),解釋器會(huì)將整個(gè)異常的堆棧信息全部輸出出來(lái)。解釋器會(huì)將異常產(chǎn)生的整個(gè)調(diào)用鏈都給打印出來(lái),那么問(wèn)題來(lái)了,我們能不能自定義這些報(bào)錯(cuò)信息呢?本文就來(lái)為大家詳細(xì)講講2022-07-07
Python OpenCV學(xué)習(xí)之圖像濾波詳解
圖像濾波的作用簡(jiǎn)單來(lái)說(shuō)就是將一副圖像通過(guò)濾波器得到另一幅圖像;明確一個(gè)概念,濾波器又被稱為卷積核,濾波的過(guò)程又被稱為卷積;實(shí)際上深度學(xué)習(xí)就是訓(xùn)練許多適應(yīng)任務(wù)的濾波器,本質(zhì)上就是得到最佳的參數(shù)。下面來(lái)跟隨小編一起深入了解一下圖像濾波吧2022-01-01
python wxpython 實(shí)現(xiàn)界面跳轉(zhuǎn)功能
wxpython沒提供界面跳轉(zhuǎn)的方式,所以就需要借助threading模塊,本文給大家分享python wxpython 實(shí)現(xiàn)界面跳轉(zhuǎn)功能,感興趣的朋友跟隨小編一起看看吧2019-12-12
Python中的response.text與content區(qū)別詳解
這篇文章主要介紹了Python中的response.text與content區(qū)別詳解,?從網(wǎng)絡(luò)請(qǐng)求下來(lái)的數(shù)據(jù),他們都是字節(jié)類型的,如果服務(wù)器不指定的話,默認(rèn)編碼是"ISO-8859-1",我們使用text直接拿到的是字符串類型,沒有進(jìn)行解碼操作,則會(huì)出現(xiàn)亂碼問(wèn)題,需要的朋友可以參考下2023-12-12
CentOS 6.5下安裝Python 3.5.2(與Python2并存)
這篇文章主要給大家介紹了在CentOS 6.5下安裝Python 3.5.2的方法教程,安裝后的python3與Python2并存,文中分享了詳細(xì)的方法步驟,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,下面來(lái)一起看看吧。2017-06-06
Python如何優(yōu)雅的實(shí)現(xiàn)自增枚舉類
枚舉類型在編程中扮演著重要的角色,它們?yōu)樽兞抠x予了更加清晰的含義,然而,在Python中,實(shí)現(xiàn)自增的枚舉類并非直接而簡(jiǎn)單的任務(wù),本文將深入討論如何通過(guò)不同的方式優(yōu)雅地實(shí)現(xiàn)自增的枚舉類,需要的朋友可以參考下2023-12-12
Python實(shí)現(xiàn)火柴人的設(shè)計(jì)與實(shí)現(xiàn)
火柴人(Stick Figure)是一種極簡(jiǎn)風(fēng)格的圖形,通常由簡(jiǎn)單的線段和圓圈組成,卻能生動(dòng)地表達(dá)人物的姿態(tài)和動(dòng)作,本文旨在介紹如何使用Python實(shí)現(xiàn)火柴人的設(shè)計(jì)與繪制,通過(guò)編程的方式,讓讀者了解火柴人背后的基本原理和實(shí)現(xiàn)方法,需要的朋友可以參考下2024-10-10

