Python之模块动态加载
1.__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
2.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
参数来指明要导入包里的哪个模块,否则会将整个包导入。
3.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
前面加一个点