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






Из документов python на __import__:
__import__( name[, globals[, locals[, fromlist[, level]]]])...
When the name variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned, not the module named by name. However, when a non-empty fromlist argument is given, the module named by name is returned. This is done for compatibility with the bytecode generated for the different kinds of import statement; when using "import spam.ham.eggs", the top-level package spam must be placed in the importing namespace, but when using "from spam.ham import eggs", the spam.ham subpackage must be used to find the eggs variable. As a workaround for this behavior, use getattr() to extract the desired components. For example, you could define the following helper:
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 и опубликую здесь ошибку, с которой я столкнулся.
Есть кое-что, что работает так, как вы хотите: 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.7 имеет importlib, точечные пути разрешаются, как ожидалось
import importlib
foo = importlib.import_module('a.dotted.path')
instance = foo.SomeClass()
Также существует пакет python 2.6, который поддерживает эту функциональность. pypi.python.org/pypi/importlib
Для 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
Как объясняется в документации, есть более простое решение:
Если вы просто хотите импортировать модуль (потенциально внутри пакета) по имени, вы можете вызвать __import __ (), а затем найти его в sys.modules:
>>> import sys
>>> name = 'foo.bar.baz'
>>> __import__(name)
<module 'foo' from ...>
>>> baz = sys.modules[name]
>>> baz
<module 'foo.bar.baz' from ...>
Как я это сделал
foo = __import__('foo', globals(), locals(), ["bar"], -1)
foobar = eval("foo.bar")
тогда я могу получить доступ к любому контенту с помощью
foobar.functionName()
Это очень полезно, однако в моей программе нет никакой другой необходимости в скручивании. Хотя, как основатель (!), Вы, наверное, лучше меня осведомлены о возможностях (никогда этим не пользовались).