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, 3)
  
# 減法
sub = count.my_sub(6, 2)
  
print("sum: {}, sub: {}".format(sum, sub))

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

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

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

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

不過,上面還存在一點點小問題:那就是我們的模塊有可能不是在本級目錄中存放着,有可能是如下圖存放方式:
在這裏插入圖片描述
那怎麼辦呢?看下面。

imp = input("請輸入你想導入的模塊名稱:")
count = __import__('first_level.{}'.format(imp), fromlist=True)
  
fun = input("請輸入你想要使用的函數名:")
  
f = getattr(count, fun, None)
  
# 加法
sum = f(2, 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學習聚集地,[點擊進入],這裏有我收集以前學習心得,學習筆記,還有一線企業的工作經驗,且給大定on零基礎到項目實戰的資料,大家也可以在下方,留言,把不懂的提出來,大家一起學

習進步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章