__import__ Python не работает должным образом

При использовании __import__ с именем, разделенным точками, например: somepackage.somemodule, возвращаемый модуль не является somemodule, все, что возвращается, кажется в основном пустым! что тут происходит?


person dwestbrook    schedule 17.10.2008    source источник


Ответы (6)


Из документов python на __import__:

__import__( name[, globals[, locals[, fromlist[, level]]]])

...

Когда переменная name имеет форму package.module, обычно возвращается пакет верхнего уровня (имя до первой точки), а не модуль, названный по имени. Однако, когда задан непустой аргумент fromlist, возвращается модуль, названный по имени. Это сделано для совместимости с байт-кодом, сгенерированным для различных типов операторов импорта; при использовании «import spam.ham.eggs» пакет спама верхнего уровня должен быть помещен в пространство имен импорта, но при использовании «from spam.ham import eggs» для поиска переменной «яйца» необходимо использовать подпакет spam.ham. . В качестве обходного пути для такого поведения используйте getattr() для извлечения нужных компонентов. Например, вы можете определить следующий помощник:

def my_import(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

Перефразируя:

Когда вы запрашиваете somepackage.somemodule, __import__ возвращает somepackage.__init__.py, которое часто бывает пустым.

Он вернет somemodule, если вы предоставите fromlist (список имен переменных внутри somemodule, которые вы хотите, которые на самом деле не возвращаются)

Вы также можете, как и я, использовать функцию, которую они предлагают.

Примечание. Я задал этот вопрос, полностью намереваясь ответить на него сам. В моем коде была большая ошибка, и, неправильно диагностировав ее, мне потребовалось много времени, чтобы понять ее, поэтому я решил помочь сообществу SO и опубликовать здесь ошибку, с которой я столкнулся.

person dwestbrook    schedule 17.10.2008

python 2.7 имеет importlib, точечные пути разрешаются, как и ожидалось

import importlib
foo = importlib.import_module('a.dotted.path')
instance = foo.SomeClass()
person cerberos    schedule 28.02.2011
comment
Также существует пакет python 2.6, поддерживающий эту функциональность. pypi.python.org/pypi/importlib - person melinath; 15.03.2013

Существует более простое решение, как описано в документации:

Если вы просто хотите импортировать модуль (возможно, внутри пакета) по имени, вы можете вызвать __import__(), а затем найти его в sys.modules:

>>> import sys
>>> name = 'foo.bar.baz'
>>> __import__(name)
<module 'foo' from ...>
>>> baz = sys.modules[name]
>>> baz
<module 'foo.bar.baz' from ...>
person Paolo    schedule 05.08.2011

Есть кое-что, что работает так, как вы хотите: twisted.python.reflect.namedAny:

>>> from twisted.python.reflect import namedAny
>>> namedAny("operator.eq")
<built-in function eq>
>>> namedAny("pysqlite2.dbapi2.connect")
<built-in function connect>
>>> namedAny("os")
<module 'os' from '/usr/lib/python2.5/os.pyc'>
person Glyph    schedule 18.10.2008
comment
Это очень полезно, однако в моей программе больше нет нужды в Twisted. Хотя, как основатель (!), вы, наверное, лучше меня разбираетесь в возможностях (никогда не пользовался). - person dwestbrook; 18.10.2008

Для Python 2.6 я написал этот фрагмент:

def import_and_get_mod(str, parent_mod=None):
    """Attempts to import the supplied string as a module.
    Returns the module that was imported."""
    mods = str.split('.')
    child_mod_str = '.'.join(mods[1:])
    if parent_mod is None:
        if len(mods) > 1:
            #First time this function is called; import the module
            #__import__() will only return the top level module
            return import_and_get_mod(child_mod_str, __import__(str))
        else:
            return __import__(str)
    else:
        mod = getattr(parent_mod, mods[0])
        if len(mods) > 1:
            #We're not yet at the intended module; drill down
            return import_and_get_mod(child_mod_str, mod)
        else:
            return mod
person David Seddon    schedule 30.03.2011

То, как я это сделал,

foo = __import__('foo',  globals(), locals(), ["bar"], -1)
foobar = eval("foo.bar")

тогда я могу получить доступ к любому контенту от

foobar.functionName()
person rahul mishra    schedule 19.08.2014