Подтвердить что ты не робот

Как правильно использовать функцию импорта 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'>
4b9b3361

Ответ 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