Pregunta

Cuando se usa __import__ con un nombre de puntos, algo así como: somepackage.somemodule , el módulo devuelto no es somemodule , lo que sea devuelto parece estar mayormente vacío! ¿Qué está pasando aquí?

¿Fue útil?

Solución

De los documentos de python en __import__ :

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

...

     

Cuando la variable de nombre es de la forma   package.module, normalmente, el   paquete de nivel superior (el nombre hasta   se devuelve el primer punto), no el   módulo nombrado por su nombre. Sin embargo, cuando un   se proporciona un argumento de la lista no vacía,   se devuelve el módulo nombrado por nombre.   Esto se hace por compatibilidad con   el bytecode generado para el   diferentes tipos de declaración de importación;   cuando se utiliza " import spam.ham.eggs " ;, el   se debe colocar el paquete de spam de nivel superior   en el espacio de nombres de importación, pero cuando   utilizando " from spam.ham import eggs " ;, el   El subpaquete spam.ham debe usarse para   Encuentra los huevos variables. Como un   solución para este comportamiento, use   getattr () para extraer el deseado   componentes Por ejemplo, podrías   defina el siguiente ayudante:

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

Parafraseando:

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

Devolverá 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 intención de responderla yo mismo. Había un gran error en mi código, y después de haberlo diagnosticado erróneamente, me tomó mucho tiempo resolverlo, así que pensé que ayudaría a la comunidad SO y publicaría el problema que encontré aquí.

Otros consejos

python 2.7 tiene importlib, las rutas punteadas se resuelven como se esperaba

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

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 su 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 ...>

Hay algo que funciona como lo deseas: 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'>

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

La forma en que lo hice es

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

entonces puedo acceder a cualquier contenido desde

foobar.functionName()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top