运行存储在列表中的单个python导入语句

运行存储在列表中的单个python导入语句,python,python-3.x,python-2.7,python-import,try-except,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:

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

基本上,我想这样做:

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
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:
        exec(statement)
    except ImportError as e:
        continue
我之所以要这样做,是因为列表中的一些库可能不在文件系统中,我不希望一次失败就让整个文件抛出导入错误

我该怎么做?

您可以这样尝试:

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
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:
        exec(statement)
    except ImportError as e:
        continue
说明:


使用
exec()
迭代列表中的每个元素,可以执行那些
import
语句。因此,如果没有错误,它将首先导入模块,您可能实际上不想这样做,如果您解释了为什么您会这样做,我们可能会向您展示一种更好的方法

但在某些情况下,这可能是合理的。例如,我可以想象一个
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:
/
,除了NameError:
测试

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

如果您想使每一个都成为1行而不是4行,您可以使用以下方法来实现,但需要重复:

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
访问它们,这也很简单:

globals().update(mods)

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


但是请注意,除了必须以这种方式比使用其他动态选项重复更多的内容之外,如果不解析
exec
块中的语句,您也无法执行任何明智的操作,例如
x=None
,因为否则您就没有名称
x
。在这种情况下,这并不困难,但它增加了更大的复杂性,代码气味…

execute语句
更改为
exec(statement)
忽略错误并将下一条语句导入
pass
,如果您确实需要动态执行,那么您就可以继续了,与其列出要执行的语句,不如列出要尝试加载的模块,然后编写一个函数,使用
importlib
(参见)尝试加载每个语句,然后对列表中的每个元素调用该函数。但如果出于某种原因必须使用语句,您可以使用它们。同时,您计划如何处理代码中稍后失败的模块?您不想每次使用
x
时都尝试:x.spam
,除了name错误:pass
,是吗?如果你能提供一个现实的例子,那么向你展示一个完整的答案会更容易。(您可以使用静态
try:from path1.path2.path3 import x编写它,除了:pass
,然后询问如何使这些尝试导入动态且减少重复。)感谢您指出我方法中的缺陷,@abarnert。@random Named User:这在我的电脑上进行了测试。您得到了所需的吗?听起来很棒!!为答案付出了惊人的努力,谢谢!