Выполнить отдельные операторы импорта Python, которые хранятся в списке - PullRequest
0 голосов
/ 23 мая 2018

У меня есть список библиотек, которые я хотел бы импортировать, но некоторые из них могут отсутствовать в файловой системе.

По сути, я хочу сделать что-то вроде этого:

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 голосов
/ 23 мая 2018

Во-первых, вы, вероятно, на самом деле не хотите этого делать - и если бы вы объяснили, почему вы так думаете, мы могли бы показать вам лучший способ сделать это.

Но в некоторых случаяхэто может быть разумноНапример, я мог бы представить файл 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: / except NameError:.поверх вашего кода.

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

Если вы хотите сделать каждый из них одним, а не четырьмя, вы можете сделать это, используя importlib, встоимость повторения:

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:

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 блок, потому что иначе у вас нет названия x.Это не совсем сложно в этом случае, но это добавляет еще больше сложности и запаха кода ...

0 голосов
/ 23 мая 2018

Вы можете попробовать вот так:

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 операторы.Так что, если нет ошибки, он импортирует эти модули

...