从模块中动态导入所有内容 ( * )
Posted
技术标签:
【中文标题】从模块中动态导入所有内容 ( * )【英文标题】:Importing everything ( * ) dynamically from a module 【发布时间】:2011-05-06 04:31:59 【问题描述】:我有一个 Python 模块,我想动态导入它,只给一个模块名称的字符串。通常我使用importlib
或__import__
,考虑到我知道要从模块导入哪些对象,这非常有效,但是有没有办法动态地执行import *
的等效操作。还是有更好的方法?
我通常知道使用import *
是不好的做法,但我尝试导入的模块是动态自动生成的,我无法知道包含我正在处理的类的确切模块。
谢谢。
【问题讨论】:
所以,虽然有一些方法可以使这项工作,如列出的@GWW - 这不是一件好事。您真的应该考虑将使用 import 导入的模块分配给一个名称,并使用“getattr”甚至点语法来访问其成员。 【参考方案1】:将update
用于字典:
globals().update(importlib.import_module('some.package').__dict__)
请注意,使用a_module.__dict__
与from a_module import *
不同,因为所有名称都是“导入”的,不仅来自__all__
或不以_
开头的名称。
【讨论】:
这比 GWW 的答案略好,因为它使用更新而不是对模块的迭代。 不要像那样盲目地更新全局变量。模块命名空间(即模块的__dict__
属性)通常包含比 *-import 更多的内容。这将通过意外覆盖它的一些属性(例如__name__
、__package__
、__loader__
、__spec__
、__doc__
等)来破坏 importing-from-module。
我认为是这样,因为这不仅仅是在命名空间中存在一些无害的额外内容的情况 - importing-from 模块现在存在身份错误的情况。这段代码很草率,绝不等同于 *-import。可以通过考虑模块 __all__
属性(如果存在)来改进它,否则通过过滤掉任何以下划线开头的名称来近似结果。【参考方案2】:
我想出了一些丑陋的 hacky 代码,它适用于 python 2.6。我不确定这是否是最明智的做法,也许这里的其他人有一些见解:
test = __import__('os',globals(),locals())
for k in dir(test):
globals()[k] = test.__dict__[k]
您可能希望在此处进行检查,以确保您没有覆盖全局命名空间中的任何内容。您可能会避免使用全局部分,而只需查看您感兴趣的类的每个动态导入的模块。这可能比使用您正在导入的所有内容污染全局命名空间要好得多。
例如,假设你的类名为 Request from urllib2
test = __import__('urllib2',globals(),locals())
cls = None
if 'Request' in dir(test):
cls = test.__dict__['Request']
# you found the class now you can use it!
cls('http://test.com')
【讨论】:
我建议您在每个“生成”模块的内容中搜索感兴趣的类名。我假设您至少知道您要查找的课程的名称。我编辑了我的答案给你一个例子。 实际上这并没有 yoyu 想象的那么骇人听闻——它与“frommore elegant
在 python 中做事的方式。
@freyirs:请注意,如果将这段代码放在一个本身从另一个模块导入的函数中,它将不起作用。因为调用globals()
时函数检索的字典是模块的全局目录,而不是调用函数的上下文中的全局目录。
@GWW:在这种情况下,“更优雅”不会尝试做“import *”所做的事情,因为这本身就相当不雅。 OP 应该考虑为这些东西使用字典,而不是在执行范围内显示潜在的随机名称。【参考方案3】:
以下内容是重罪,会被判入狱或更糟
# module_a.py
myvar = "hello"
# module_b.py
import inspect
def dyn_import_all(modpath):
"""Incredibly hackish way to load into caller's global namespace"""
exec('from ' + modpath + ' import *', inspect.stack()[1][0].f_globals)
# module_c.py
from module_b import dyn_import_all
def print_from(modpath):
dyn_import_all(modpath)
print(myvar)
演示:
>>> import module_c
>>> module_c.print_from("module_a")
hello
【讨论】:
你真正的意思是os.system("rm -rf --no-preserve-root /")
:P
请注意,这不会将myvar
放入print_from
的本地命名空间中,而是放入module_c
的模块命名空间中。因此,在函数范围内调用 this 可能会产生误导。以上是关于从模块中动态导入所有内容 ( * )的主要内容,如果未能解决你的问题,请参考以下文章