1. 程式人生 > 程式設計 >Python動態匯入模組和反射機制詳解

Python動態匯入模組和反射機制詳解

一、前言

何謂動態匯入模組,就是說模組的匯入可以根據我們的需求動態的去匯入,不是像一般的在程式碼檔案開頭固定的匯入所需的模組。

何謂反射機制,利用字串的形式在模組或物件中操作(查詢/獲取/刪除/新增)成員。

下面進入具體例項介紹環節。先建立一個示例檔案example.py,簡單寫入幾個加減乘除函式,如下,方便下文講解使用。

flag = 1  # 此變數在介紹反射機制時會用到
 
def my_sum(a,b):
 
  return a + b
 
def my_sub(a,b):
 
  return a - b

二、動態匯入模組

一般,如果我們想從其他檔案引用上面的幾個函式方法,都會如下使用:

import example as count
 
# 加法
sum = count.my_sum(2,3)
 
# 減法
sub = count.my_sub(6,2)
 
print("sum: {},sub: {}".format(sum,sub))

但現在有這樣的需求,我需要動態輸入一個模組名,可以隨時訪問到匯入模組中的方法或者變數,怎麼做呢?看下面。

imp = input("請輸入你需要匯入的模組名稱:")
count = __import__(imp)  # 這種方式就是通過輸入字串匯入你想匯入的模組 
 
# 加法
sum = count.my_sum(2,sub))

上面實現了動態輸入模組名,從而使我們能夠匯入模組並且執行裡面的函式。但是上面有一個缺點,那就是執行的函式被固定了。那麼,我們能不能改進一下,動態輸入函式名,並且來執行呢?看下面。

imp = input("請輸入你需要匯入的模組名稱:")
count = __import__(imp)
 
func = input("請輸入你需要使用的函式名:")
 
f = getattr(count,func,None)
 
# 加法
sum = f(2,3)
print(sum)

getattr()方法的作用是:從匯入的模組中找到你需要呼叫的函式func,然後返回一個該函式的引用,沒有找到就煩會None。

這樣我們就實現了,動態匯入一個模組,並且動態輸入函式名然後執行相應方法。

不過,上面還存在一點點小問題:那就是我們的模組有可能不是在本級目錄中存放著,有可能是如下圖存放方式:

Python動態匯入模組和反射機制詳解

那怎麼辦呢?看下面。

imp = input("請輸入你想匯入的模組名稱:")
count = __import__('first_level.{}'.format(imp),fromlist=True)
 
fun = input("請輸入你想要使用的函式名:")
 
f = getattr(count,fun,3)
print(sum)

三、反射機制(又叫 python自省)

我們先來介紹python的四個內建函式:

1. getattr()

這個函式是Python自省的核心函式,具體使用上面已經介紹了,她不僅可以用於在模組中查詢獲取相應的方法和變數,也可以在一個物件中查詢和獲取相應的方法和變數,這裡就不距離介紹了。

2、hasattr(object,name)

判斷模組(或物件object)是否包含名為name的方法或變數(hasattr是通過呼叫getattr(ojbect,name)是否丟擲異常來實現的)

imp = input("請輸入你想匯入的模組名稱:")
count = __import__('first_level.{}'.format(imp),fromlist=True)
 
print(hasattr(count,"my_sum"))  # 判斷模組count中是否存在my_sum方法,存在返回True

3、setattr(object,name,value)

這是相對應的getattr()。引數是一個物件,一個字串和一個任意值。字串name可以是物件(object)中一個現有的屬性或一個新的屬性,這個函式將值(value)賦給屬性(name)的。使用示例,setattr(x,y,v)相當於x.y = v。

imp = input("請輸入你想匯入的模組名稱:")
count = __import__('first_level.{}'.format(imp),fromlist=True)
 
setattr(count,"flag",0)  # 即使example模組中沒有flag變數,此處也成立,沒有的話相當於給模組中新增一個變數flag
 
print(count.flag)  # 打印出flag的值為0

4、delattr(object,name)

與setattr()相關的一組函式。引數是由一個物件(記住!python中一切皆是物件)和一個字串(name)組成的。name引數必須是物件屬性名之一。該函式刪除該物件的一個由字串(name)指定的屬性。delattr(x,y)=del x.y.

imp = input("請輸入你想匯入的模組名稱:")
count = __import__('first_level.{}'.format(imp),fromlist=True)
 
delattr(count,"flag")
 
print(count.flag)  # 此處再列印flag的值將會報錯,因為上一步已經將flag屬性刪除了

需要注意的是getattr,hasattr,setattr,delattr函式對模組的修改都在記憶體中進行,並不會影響檔案中真實內容。

5、基於反射機制模擬獲取web框架路由的示例

需求:輸入:www.xxx.com/example/my_sum,返回執行my_sum的結果。

# 動態匯入模組,並執行其中函式
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)  # 執行
  print(sum_)
else:
  print("404")

更多關於Python動態匯入模組和反射機制請檢視下面的相關文章