Python:如何从模块动态导入所有方法和属性
我想动态加载一个模块,给定它的字符串名(来自环境变量)。我正在使用Python 2.7。我知道我可以做一些事情,比如:Python:如何从模块动态导入所有方法和属性,python,python-2.7,python-import,python-importlib,Python,Python 2.7,Python Import,Python Importlib,我想动态加载一个模块,给定它的字符串名(来自环境变量)。我正在使用Python 2.7。我知道我可以做一些事情,比如: import os, importlib my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE')) 这大致相当于 import my_settings from my_settings import * (其中SETTINGS\u模块='my\u SETTINGS')。问题是,我需要的东西
import os, importlib
my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE'))
这大致相当于
import my_settings
from my_settings import *
(其中SETTINGS\u模块='my\u SETTINGS'
)。问题是,我需要的东西相当于
import 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中,是否有一种方法可以动态导入模块的所有方法和属性?如果您有模块对象,您可以模仿
导入*
使用的逻辑,如下所示:
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})
然而,这几乎肯定是一个非常糟糕的主意。您将随意践踏任何具有相同名称的现有变量。通常,当您从blah import*执行
时,这已经够糟糕的了,但是当您动态执行时,对于哪些名称可能会发生冲突,存在更多的不确定性。您最好只导入my_模块
,然后使用常规属性访问(例如my_模块.someAttr
)从中访问所需内容,或者getattr
如果你需要动态访问它的属性。我的情况有点不同-想要动态导入每个gameX中的constants.py名称。uuuu init_uuuuuuuy.py
模块(见下文),因为静态导入这些将永远留在sys.modules中(见:这是我从Beazley挑选的)
以下是我的文件夹结构:
game/
__init__.py
game1/
__init__.py
constants.py
...
game2/
__init__.py
constants.py
...
每个gameX.\uuuu init\uuuuuuuuupy
导出一个init()方法-因此我最初在所有gameX.\uuuuu init\uuuuuuuuupy
中都有一个from.constants import*
,我试图将其移到init()方法中
我的第一次尝试是:
@-275,2+274,6@@def init():
#调用而不是“重新加载”
+牦牛={}
+yak.update(locals())
+from.constants import*#在此失败
+yak={x:y代表x,y在局部变量中()如果x不在yak}
+globals().update(yak)
brec.ModReader.recHeader=记录头
失败的原因相当隐晦:
SyntaxError:函数“init”中不允许导入*,因为它包含带有自由变量的嵌套函数
我可以向您保证,其中没有嵌套函数。不管怎样,我进行了黑客攻击,最终得到了:
def init():
# ...
from .. import dynamic_import_hack
dynamic_import_hack(__name__)
在游戏中的何处。\uuuu init\uuuuuuuuuuupy
:
def dynamic\u import\u hack(包名称):
打印_name _#game.init
打印包_name#game.gameX.init
导入导入库
常量=importlib.import_模块('.constants',package=package_名称)
导入系统
对于dir中的k(常数):
如果k.startswith(“”“):继续
setattr(sys.modules[package_name],k,getattr(constants,k))
(有关setattr,请参阅,而关于getattr,我更喜欢使用它们,而不是直接访问\uuuu dict\uuuu
)
这是可行的,它比公认答案中的方法更通用,因为它允许您在一个地方使用黑客,并从任何模块使用它。然而,我并不确定这是实施它的最佳方式——我打算问一个问题,但由于这将是一个重复的问题,我将其作为一个答案发布,并希望得到一些反馈。我的问题是:
- 为什么在没有嵌套函数的情况下,函数“init”中不允许使用此“SyntaxError:import*
- dir有很多警告——特别是它试图产生最相关的信息,而不是完整的信息——这让我有点担心
- 是否没有内置的方法来执行
导入*
?即使在Python3中
没有准确回答所述问题,但如果您希望将文件作为动态模块的代理,您可以使用在模块级别定义\uuu getattr\uuu
的功能
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)
您不能简单地使用eval
?我决定只设置Django的Django_SETTINGS_模块环境变量,而不是将变量加载到default SETTINGS.py中。看起来这是正确的答案,所以谢谢你的帮助!我自由地编辑了与import*
行为更匹配的代码。如果我出错或更改了意图,请随时恢复。此顶级代码是从文件结构的哪一部分运行的?正如在对原始问题的评论中所建议的,你能用eval
来做这件事吗?@sundance:我知道了eval是什么,然后我忘记了:P-gameX init文件是动态导入的,然后我们保留了我们需要的文件-我们需要这样做以确保这些文件在那里并且工作,但是现在您提到它,我们最好避免这种情况——请参阅:(此代码还导入了所有其他代码——我在这里发布的代码仍然位于我的本地树上)