运行存储在列表中的各个python import语句

时间:2018-05-23 06:13:59

标签: python python-3.x python-2.7 python-import try-except

我有一个我要导入的库列表,但其中一些可能不在文件系统中。

基本上,我想做这样的事情:

list_of_imports = ['from path1.path2.path3 import x', 'from path1.path2.path4 import y', 'from path1.path2.path3 import z', 'from path1.path2.path2 import a']

for statement in list_of_imports:
    try:
        execute statement
    except:
        ignore error and import the next statement

我想这样做的原因是因为列表中的某些库可能不在文件系统中,并且我不希望一个失败导致整个文件抛出导入错误。

我该怎么做?

2 个答案:

答案 0 :(得分:2)

您可以尝试这样:

exec()

说明:

使用import对列表中的每个元素进行迭代,您可以执行这些try..catch语句。因此,如果没有错误,它将导入该模块

答案 1 :(得分:1)

首先,你可能实际上并不想这样做 - 如果你解释了为什么这么做,我们可能会告诉你一个更好的方法。

但在某些情况下,这可能是合理的。例如,我可以想象一个PYTHONSTARTUP文件为一个交互式会话预加载一堆模块;作为交互式用户,您可以查看已加载的内容并决定要执行的操作。

如果您只需要其中的一小部分,最好明确地执行这些操作:

try:
    from path1.path2.path3 import x
except ImportError:
    pass
try:
    from path1.path2.path4 import y
except ImportError:
    pass
try:
    from path1.path2.path3 import z
except ImportError:
    pass

除了交互式使用之外的任何其他内容,你可能真的想要x = None而不是pass,除非你想包装一堆try: / {{1在你的代码中测试。

except NameError:

如果你想让每一个都成为1-liner而不是4-liner,你可以使用importlib来做到这一点,代价是重复自己:

try:
    from path1.path2.path3 import x
except ImportError:
    x = None
# etc.

如果您需要完成大量这些操作,最好再次使用from importlib.util import find_spec if find_spec('path1.path2.path3.x'): from path1.path2.path3 import x if find_spec('path1.path2.path4.y'): from path1.path2.path4 import y if find_spec('path1.path2.path3.z'): from path1.path2.path3 import z 编写包装函数:

importlib

如果您有动态生成的模块列表,则需要弄清楚如何存储结果,因为您可能还需要动态访问它们。一个明显的可能性是将它们粘在一个词典中:

import importlib
def try_import(mod):
    try:
        return importlib.import_module(mod)
    except ImportError:
        return None
x = try_import('path1.path2.path3.x')
y = try_import('path1.path2.path4.y')
z = try_import('path1.path2.path3.z')

...或者,如果您想跳过缺少的模块而不是使用import importlib def try_import(mod): try: return importlib.import_module(mod) except ImportError: return None names = ['path1.path2.path3.x', 'path1.path2.path4.y', 'path1.path2.path3.z'] mods = [try_import(name) for name in names] mods = {name.split('.')[-1]: mod for name, mod in zip(names, mods)}

None

...或者,如果这是针对准静态的东西,比如交互式示例,可能是命名空间,因此您只需访问mods = {name.split('.')[-1]: mod for name, mod in zip(names, mods) if mod}

mods.x

...或者,如果你想将它们转储成全局变量,那么你可以像import types mods = types.SimpleNamespace(**mods) 那样访问它们,这很简单:

x

如果您确实需要构建语句列表而不是模块列表,请使用exec

globals().update(mods)

但请注意,除了必须以这种方式重复自己而不是其他动态选项之外,如果不解析statements = ['from path1.path2.path3 import x', 'from path1.path2.path4 import y'] for statement in statements: try: exec(statement) except ImportError: pass 块内的语句,您也无法做出像x = None那样合理的事情。 ,因为否则您没有名称exec。在这种情况下,这并不完全是 hard ,但它增加了更多的复杂性和代码味道......