При использовании __import__
с именем, разделенным точками, например: somepackage.somemodule
, возвращаемый модуль не является somemodule
, все, что возвращается, кажется в основном пустым! что тут происходит?
__import__ Python не работает должным образом
Ответы (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 и опубликовать здесь ошибку, с которой я столкнулся.
python 2.7 имеет importlib, точечные пути разрешаются, как и ожидалось
import importlib
foo = importlib.import_module('a.dotted.path')
instance = foo.SomeClass()
Существует более простое решение, как описано в документации:
Если вы просто хотите импортировать модуль (возможно, внутри пакета) по имени, вы можете вызвать __import__(), а затем найти его в sys.modules:
>>> import sys
>>> name = 'foo.bar.baz'
>>> __import__(name)
<module 'foo' from ...>
>>> baz = sys.modules[name]
>>> baz
<module 'foo.bar.baz' from ...>
Есть кое-что, что работает так, как вы хотите: 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'>
Для 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
То, как я это сделал,
foo = __import__('foo', globals(), locals(), ["bar"], -1)
foobar = eval("foo.bar")
тогда я могу получить доступ к любому контенту от
foobar.functionName()