我想动态加载一个模块,给定它的字符串名称(来自环境变量)。我正在使用Python 2.7。我知道我可以这样做:
import os, importlib
my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE'))
这大致相当于
import my_settings
(其中SETTINGS_MODULE = 'my_settings'
)。问题是,我需要等同于
from my_settings import *
因为我希望能够访问模块中的所有方法和变量。我试过了
import os, importlib
my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE'))
from my_module import *
但我得到了一堆错误。有没有办法在Python 2.7中动态导入模块的所有方法和属性?
答案 0 :(得分:16)
如果您有模块对象,则可以模仿import *
使用的逻辑,如下所示:
module_dict = my_module.__dict__
try:
to_import = my_module.__all__
except AttributeError:
to_import = [name for name in module_dict if not name.startswith('_')]
globals().update({name: module_dict[name] for name in to_import})
然而,这几乎肯定是一个非常糟糕的主意。你将毫不客气地踩踏任何具有相同名称的现有变量。当你正常from blah import *
时,这已经足够糟糕了,但是当你动态地做这件事时,关于名字可能会发生碰撞的更多不确定性。您最好只导入my_module
,然后使用常规属性访问(例如my_module.someAttr
)或getattr
访问您需要的内容,如果您需要动态访问其属性。
答案 1 :(得分:0)
我的情况有点不同 - 想在每个gameX.__init__.py
模块中动态导入constants.py名称(见下文),导致静态导入它们将永远留在sys.modules中(参见:this {{来自Beazley的我来自excerpt)。
这是我的文件夹结构:
game/
__init__.py
game1/
__init__.py
constants.py
...
game2/
__init__.py
constants.py
...
每个gameX.__init__.py
都会导出一个init()方法 - 所以我最初在所有from .constants import *
中都有gameX.__init__.py
我尝试在init()方法中移动。
我的第一次尝试:
@@ -275,2 +274,6 @@ def init():
# called instead of 'reload'
+ yak = {}
+ yak.update(locals())
+ from .constants import * # fails here
+ yak = {x: y for x,y in locals() if x not in yak}
+ globals().update(yak)
brec.ModReader.recHeader = RecordHeader
相当神秘的失败:
语法错误:函数'init'中不允许import *,因为它包含带有自由变量的嵌套函数
我可以向你保证,那里没有嵌套函数。无论如何,我砍掉并砍掉了最后:
def init():
# ...
from .. import dynamic_import_hack
dynamic_import_hack(__name__)
game.__init__.py
中的位置:
def dynamic_import_hack(package_name):
print __name__ # game.init
print package_name # game.gameX.init
import importlib
constants = importlib.import_module('.constants', package=package_name)
import sys
for k in dir(constants):
if k.startswith('_'): continue
setattr(sys.modules[package_name], k, getattr(constants, k))
(对于setattr,请参阅this related question,而对于getattr How can I add attributes to a module at run time? - 我更喜欢使用那些而不是直接访问__dict__
)
这是有效的,它比接受答案中的方法更通用,因为它允许你在一个地方进行黑客攻击并从任何模块中使用它。但是我并不确定这是实现它的最佳方式 - 我会问一个问题,但因为这将是一个问题的副本,我将其作为答案发布,并希望得到一些反馈。我的问题是:
import *
吗?甚至在python 3?答案 2 :(得分:0)
不能精确地回答措辞上的问题,但是如果您希望将文件作为动态模块的代理,则可以使用在模块级别定义__getattr__
的功能。
import importlib
import os
module_name = os.environ.get('CONFIG_MODULE', 'configs.config_local')
mod = importlib.import_module(module_name)
def __getattr__(name):
return getattr(mod, name)