如何在Python中调用“from x import *”,其中x是一个变量

3
我正在运行几个Python脚本,这些脚本除了变量前缀外完全相同。(仅为清晰起见,我正在使用Tweepy和Twitter API)
我已经为每个API凭据命名为xx_apicred.pyyy_apicred.py等,并将其保存为文件夹中的单独文件。
此外,我有名为xx_infoyy_info等的表格。通过字符串操作很容易更改此部分内容。
我想将其更改为一个文件,其中传递xx字符串作为参数。这对除from xx_cred import*之外的所有内容都有效。
当我将它替换为一个字符串变量时,我会得到错误消息:ImportError: No module named 'var' 有没有办法通过变量导入?
3个回答

2
这将允许字符串作为模块名称:
import importlib

cred = importlib.import_module('{}_cred'.format(impl))

其中impl是所选实现的'xx''yy'

许多Python库都使用这个技巧(tornado,rethinkdb...)

现在可以像这样使用:

cred.module_var

如果你真的想要使用 from module import * 的效果,请使用以下代码:
variables = {name: value for name, value in vars(cred).items()
             if not name.startswith('__')}
globals().update(variables)

但是不建议使用import *


我已经尝试过这个,但它找不到模块。我之后尝试了 import cred,但它找不到 cred 模块。 - pekasus
太棒了!它有效了。谢谢!有没有办法做到 from xx import* 或者我每次都必须包含 cred.variable - pekasus
2
@pekasus 你可以使用 getattr: x = getattr(cred, 'variable')。然后你可以用 x 代替 cred.variable - user2390182
1
只需使用 variable = cred.variable 来缩短名称。 - Mike Müller
1
globals().update(vars(cred))会覆盖所有内容,包括一些应该保留的特殊值。例如,现在__name__将变成模块的名称(例如xx_cred),这意味着像if __name__ == "__main__": main()这样的代码将失败。但是,vars显然比inspect更好。 - Alex Hall
显示剩余4条评论

2

首先,让我指出,在实际代码中,“from module import *”通常被认为是不好的做法。它只是一个使解释器会话更容易的技巧。你应该使用“from module import a, b”或者“import module; module.a()”。

如果你真的想要动态地将模块中的所有名称带入当前全局命名空间,可以这样做:

import importlib

module = importlib.import_module('module')
globs = globals()
for key, value in vars(module).items():
    if key not in globs:
        globs[key] = value

这样做可以让你无需使用module的成员限定符,但是像IDE这样的工具将无法理解这个“魔法”,并认为您的变量未定义(尽管这不会阻止代码运行,只是会有突出显示的“错误”)。正如其他人所提到的那样,您最好手动创建所需的变量作为限定版本的别名,例如variable = cred.variable


1
@Apero,我不明白你是如何建议使用getattr来解决这个问题的?你在回答中没有提到它。我的答案是唯一一个实际回答了OP问题的(尽管我已经警告他他的问题是个坏主意)。获取模块对象并不等同于导入模块中的所有元素,因为你仍然需要限定模块中值的名称,而OP显然不想这样做。 - Alex Hall
我的回答只是提供信息而不是答案。我不赞成使用 from module import *,我总是使用 import module 然后使用 module.something。所以如果 OP 也是这样做的话,一个简单的 getattr 就可以让他轻松地完成任务,但是他应该像选定的答案建议的那样只加载模块并动态执行 module.something。 - DevLounge

0

仅供参考 不要选择为最佳答案

这是Rethink DB内部的实现方式,基于用户设置的循环类型:

def set_loop_type(library):
    global connection_type

    # find module file
    moduleName = 'net_%s' % library
    modulePath = None
    driverDir = os.path.realpath(os.path.dirname(__file__))
    if os.path.isfile(os.path.join(driverDir, library + '_net', moduleName + '.py')):
        modulePath = os.path.join(driverDir, library + '_net', moduleName + '.py')
    else:
        raise ValueError('Unknown loop type: %r' % library)

    # load the module
    moduleFile, pathName, desc = imp.find_module(moduleName, [os.path.dirname(modulePath)])
    module = imp.load_module('rethinkdb.' + moduleName, moduleFile, pathName, desc)

imp 是一个你也可以利用的有用的 Python 库。


imp 的文档中:在大多数情况下,建议您考虑使用 importlib 模块的功能而不是使用此模块。 - Mike Müller
告诉RethinkDB开发人员吧;-)也许这属于一些边缘情况,其中impl更好。 - DevLounge
importlib: 自3.1版本开始新增自2.7版本开始新增。因此,这段RethinkDB代码可能早于这些版本。 - Mike Müller
是的,他们肯定希望与尽可能多的版本兼容,这对于数据库驱动程序来说是可以理解的。 - DevLounge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接