Python __import__ не работает должным образом - PullRequest
43 голосов
/ 17 октября 2008

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

Ответы [ 6 ]

54 голосов
/ 17 октября 2008

Из документации по питону __import__:

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

...

Когда переменная имени имеет форму 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 и опубликовать ошибку, с которой столкнулся здесь.

32 голосов
/ 28 февраля 2011

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

import importlib
foo = importlib.import_module('a.dotted.path')
instance = foo.SomeClass()
16 голосов
/ 05 августа 2011

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

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

>>> import sys
>>> name = 'foo.bar.baz'
>>> __import__(name)
<module 'foo' from ...>
>>> baz = sys.modules[name]
>>> baz
<module 'foo.bar.baz' from ...>
7 голосов
/ 18 октября 2008

Есть то, что работает так, как вы хотите: 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'>
1 голос
/ 30 марта 2011

Для 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
0 голосов
/ 19 августа 2014

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

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

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

foobar.functionName()
...