__import__
項目裡很經常見到這樣的場景,根據環境變量,加載不同的配置。
測試環境:config_dev.py
db_host = '127.0.0.1'
正式環境:config_pro.py
db_host = '192.168.0.1'
這種情況就可以用__import__
來動態加載,簡單示例如:
project_env = 'dev'
if project_env == 'dev':
config = __import__("config_dev")
else:
config = __import__("config_pro")
print(config.db_host)
# 結果:
# 127.0.0.1
fromlist
__import__
有很多參數,其中name
是必須的,其它參數中fromlist
是一個比較重要的參數。在上一個示例中,兩份配置與引入模塊的文件是在同一個文件夾下,那不在呢?現在,更改項目結果 :
├── conf
│ ├── __init__.py
│ ├── config_dev.py
│ └── config_pro.py
└── demo.py
改一下demo.py
的代碼:
project_env = 'dev'
if project_env == 'dev':
config = __import__("conf.config_dev")
else:
config = __import__("conf.config_pro")
print(config)
輸出結果:
<module 'conf' from 'D:\\project\\python\\black_api\\demo\\conf\\__init__.py'>
看出來了嗎?我們的本意是想導入不同的模塊,config_dev
或config_pro
,但實際導入的是conf
模塊,與我們預期不符。這種情況下,需要使用fromlist
參數:
project_env = 'pro'
if project_env == 'dev':
config = __import__("conf.config_dev", fromlist="config_dev")
else:
config = __import__("conf.config_pro", fromlist="config_pro")
print(config)
輸出結果:
<module 'conf.config_pro' from 'D:\\project\\python\\black_api\\demo\\conf\\config_pro.py'>
結論:在使用__import__
函數時,name
的地址如果包含了包的名字, 一定要使用fromlist
參數來指明要導入包裡的哪個模塊,否則會將整個包導入。
importlib.import_module
importlib
模塊的import_module
方法相比於__import__
更加友好,使用起來更加方便。還是以示例2的項目結構,修改demo.py
的代碼:
import importlib
project_env = 'dev'
if project_env == 'dev':
# 絕對導入
config = importlib.import_module('conf.config_dev')
else:
# 相對導入
config = importlib.import_module('.config_pro', package='conf')
print(config.db_host)
使用相對導入時,務必在name
前面加一個點