top from example beyond attempted another __all__ python python-import

from - python import file



Python''s__import__ no funciona como se esperaba (6)

De los documentos de python en __import__ :

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

...

Cuando la variable de nombre tiene el formato package.module, normalmente se devuelve el paquete de nivel superior (el nombre hasta el primer punto), no el módulo nombrado por nombre. Sin embargo, cuando se da un argumento de lista no vacía, se devuelve el módulo nombrado por nombre. Esto se hace para la compatibilidad con el bytecode generado para los diferentes tipos de declaración de importación; cuando se usa "import spam.ham.eggs", el spam de paquete de nivel superior debe colocarse en el espacio de nombre de importación, pero cuando se utiliza "from spam.ham import eggs", se debe usar el subpaquete spam.ham para encontrar los huevos variables . Como una solución para este comportamiento, use getattr () para extraer los componentes deseados. Por ejemplo, podría definir el siguiente ayudante:

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

Parafrasear:

Cuando solicite somepackage.somemodule , __import__ devuelve somepackage.__init__.py , que a menudo está vacío.

somemodule si proporciona fromlist (una lista de los nombres de variables dentro de somemodule que desea, que en realidad no se devuelven)

También puede, como lo hice, usar la función que sugieren.

Nota: Hice esta pregunta con la plena intención de responderla yo mismo. Hubo un gran error en mi código, y después de haberlo diagnosticado mal, me tomó mucho tiempo resolverlo, así que pensé que ayudaría a la comunidad SO y publicaría el gotcha con el que me encontré aquí.

Al usar __import__ con un nombre punteado, algo así como: somepackage.somemodule , el módulo devuelto no es ningún somemodule , ¡lo que se devuelve parece estar casi vacío! ¿Que está pasando aqui?


Hay algo que funciona como lo desea: 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 tiene importlib, las rutas de puntos se resuelven como se esperaba

import importlib foo = importlib.import_module(''a.dotted.path'') instance = foo.SomeClass()


Para python 2.6, escribí este fragmento:

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


Hay una solución más simple, como se explica en la documentación:

Si simplemente desea importar un módulo (potencialmente dentro de un paquete) por nombre, puede llamar a __import __ () y luego buscarlo en sys.modules:

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


La forma en que lo hice es

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

entonces puedo acceder a cualquier contenido de por

foobar.functionName()