Как правильно использовать функцию импорта python __import __()
Я пытаюсь реплицировать from foo.bar import object
с помощью функции __import__
, и я, кажется, ударил стену.
from glob import glob
легко:
glob = __import__("glob",glob)
или glob = __import__("glob").glob
Проблема заключается в том, что я импортирую из пакета (например, bar), и я хочу, чтобы script в пакете был источником импорта.
Так что мне хотелось бы что-то вроде
string_to_import = "bar"
object = __import__("foo",string_to_import).object
Но это просто импортирует __init__
в пакет foo.
Как это можно сделать?
EDIT:
Когда я использую очевидное, только __init__
называется
__import__("foo.bar")
<module 'foo' from 'foo/__init__.pyc'>
Ответы
Ответ 1
Оператор import вернет модуль верхнего уровня пакета, если вы не передадите следующие дополнительные аргументы.
_temp = __import__('foo.bar', globals(), locals(), ['object'], -1)
object = _temp.object
См. документы Python в __import__
statement
Ответ 2
Вы должны использовать importlib.import_module
, __import__
не рекомендуется за пределами интерпретатора.
В __import__
doc:
Импортировать модуль. Поскольку эта функция предназначена для использования Python интерпретатора, а не для общего использования, лучше использовать importlib.import_module() для программного импорта модуля.
Он также поддерживает относительный импорт.
Ответ 3
Вместо использования функции __import__
я бы использовал функцию getattr:
model = getattr(module, model_s)
где модуль является модулем для просмотра, а model_s - вашей модельной строкой. Функция __import__
не предназначена для использования свободно, где эта функция получит то, что вы хотите.
Ответ 4
Как правильно использовать функцию python __import__()
?
Лучше всего использовать importlib
. Но если вы настаиваете:
Тривиальное использование:
>>> sys = __import__('sys')
>>> sys
<module 'sys' (built-in)>
Сложные:
>>> os = __import__('os.path')
>>> os
<module 'os' from '/home/myuser/anaconda3/lib/python3.6/os.py'>
>>> os.path
<module 'posixpath' from '/home/myuser/anaconda3/lib/python3.6/posixpath.py'>
Если вам нужен самый правый дочерний модуль в имени, передайте непустой список, например. [None]
, fromlist
:
>>> path = __import__('os.path', fromlist=[None])
>>> path
<module 'posixpath' from '/home/myuser/anaconda3/lib/python3.6/posixpath.py'>
Или, как заявляет документация, используйте importlib.import_module
:
>>> importlib = __import__('importlib')
>>> futures = importlib.import_module('concurrent.futures')
>>> futures
<module 'concurrent.futures' from '/home/myuser/anaconda3/lib/python3.6/concurrent/futures/__init__.py'>
Документация
Документы для __import__
являются самыми плохими из встроенных функций.
__import__(...)
__import__(name, globals=None, locals=None, fromlist=(), level=0) -> module
Import a module. Because this function is meant for use by the Python
interpreter and not for general use it is better to use
importlib.import_module() to programmatically import a module.
The globals argument is only used to determine the context;
they are not modified. The locals argument is unused. The fromlist
should be a list of names to emulate ``from name import ...'', or an
empty list to emulate ``import name''.
When importing a module from a package, note that __import__('A.B', ...)
returns package A when fromlist is empty, but its submodule B when
fromlist is not empty. Level is used to determine whether to perform
absolute or relative imports. 0 is absolute while a positive number
is the number of parent directories to search relative to the current module.
Если вы внимательно прочитаете это, вы почувствуете, что API изначально был предназначен для обеспечения ленивой загрузки функций из модулей. Однако это не так, как работает CPython, и я не знаю, смогли ли это сделать другие реализации Python.
Вместо этого CPython выполняет весь код в пространстве имен модулей при первом импорте, после чего модуль кэшируется в sys.modules
.
__import__
может быть полезен. Но понимание того, что он делает на основе документации, довольно сложно.
Полное использование __import__
Чтобы адаптировать полную функциональность, чтобы продемонстрировать текущий API __import__
, здесь приведена оболочечная функция с более чистым, более документированным API.
def importer(name, root_package=False, relative_globals=None, level=0):
""" We only import modules, functions can be looked up on the module.
Usage:
from foo.bar import baz
>>> baz = importer('foo.bar.baz')
import foo.bar.baz
>>> foo = importer('foo.bar.baz', root_package=True)
>>> foo.bar.baz
from .. import baz (level = number of dots)
>>> baz = importer('baz', relative_globals=globals(), level=2)
"""
return __import__(name, locals=None, # locals has no use
globals=relative_globals,
fromlist=[] if root_package else [None],
level=level)
Чтобы продемонстрировать, например, от сестринского пакета до база:
baz = importer('foo.bar.baz')
foo = importer('foo.bar.baz', root_package=True)
baz2 = importer('bar.baz', relative_globals=globals(), level=2)
assert foo.bar.baz is baz is baz2
Динамический доступ имен в модуле
Чтобы динамически получить доступ к глобальным переменным по имени из модуля baz, используйте getattr
. Например:
for name in dir(baz):
print(getattr(baz, name))
Ответ 5
__import__("foo").__dict__["bar"].object
getattr(__import__("foo"), "bar").object # alternative version with suggestion above