我正在尝试用Python动态导入配置文件。
我使用时代码正常:
import conf.config as config
但使用时无法正常工作:
config = __import__("conf.config")
以下是示例程序和运行时得到的结果:
#regularimport.py
import conf.config as config
def read_values(cfg):
for varname in cfg.__dict__.keys():
if varname.startswith('__'):
continue
value = getattr(cfg, varname)
yield (varname, value)
for name,value in read_values(config):
print "Current config: %s = %s" % (name, value)
结果:
$python regularimport.py
Current config: SETTING_TWO = another setting
Current config: SETTING_ONE = some setting
动态导入:
#dynamicimport.py
conf_str = "conf.config"
config = __import__(conf_str)
def read_values(cfg):
for varname in cfg.__dict__.keys():
if varname.startswith('__'):
continue
value = getattr(cfg, varname)
yield (varname, value)
for name,value in read_values(config):
print "Current config: %s = %s" % (name, value)
结果:
$ python dynamicimport.py
Current config: config = <module 'conf.config' from '/home/ubuntu/importex/conf/config.pyc'>
我的问题是为什么差异?更重要的是,如何使动态导入示例与常规导入一样工作?
答案 0 :(得分:6)
正如the documentation所解释的那样:
当 name 变量的格式为
package.module
时,通常会返回顶级包(直到第一个点的名称), not 由 name 命名的模块。
所以,当你这样做时:
config = __import__("conf.config")
这与以下不一样:
import conf.config as config
而是更像是:
import conf.config
config = conf
为什么?
因为conf
而非conf.config
是受import
语句约束的事物。 (当然,在import foo as bar
中,显然bar
受到限制......但__import__
并不等同于import foo as bar
,而是import foo
。)文档进一步解释。但结果是你可能不应该首先使用__import__
。
在功能文档的最顶部,它说:
注意:这是日常Python编程中不需要的高级函数,与
importlib.import_module()
不同。
在底部,在解释了__import__
如何使用包以及它为什么以这种方式工作之后,它说:
如果您只想按名称导入模块(可能在包中),请使用
importlib.import_module()
。
因此,正如您可能猜到的,简单的解决方案是使用importlib.import_module
。
如果你必须使用Python 2.6,importlib
不存在......好吧,只有 没有简单的解决方案。您可以在imp
之外自己构建import_module
之类的内容。或者使用__import__
然后挖掘sys.modules
。或__import__
每件,然后getattr
通过结果。或者以各种其他hacky方式。是的,这很糟糕 - 这就是3.0和2.7修复它的原因。
2.6文档举了第二个hack的例子。使其适应您的情况:
__import__("conf.config")
config = sys.modules["conf.config"]
答案 1 :(得分:0)
config = __import__("conf.config")
不等同于import conf.config as config
。
例如:
>>> import os.path as path
>>> path
<module 'posixpath' from '/usr/lib/python2.7/posixpath.pyc'>
>>> __import__('os.path')
<module 'os' from '/usr/lib/python2.7/os.pyc'>
而不是__import__
使用importlib.import_module
来获取子包/子模块。
>>> import importlib
>>> importlib.import_module('os.path')
<module 'posixpath' from '/usr/lib/python2.7/posixpath.pyc'>