Question

Lors de l'utilisation de __ import __ avec un nom en pointillé, quelque chose comme: somepackage.somemodule , le module renvoyé n'est pas un module , peu importe ce qui est renvoyé. semble être la plupart du temps vide! que se passe-t-il ici?

Était-ce utile?

La solution

À partir de la documentation Python sur __ import __ :

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

...

     

Quand la variable de nom est de la forme   package.module, normalement, le   paquet de niveau supérieur (le nom jusqu’à   le premier point) est renvoyé, pas le   module nommé par nom. Cependant, quand un   l'argument fromlist non vide est donné,   le module nommé par nom est renvoyé.   Ceci est fait pour la compatibilité avec   le bytecode généré pour le   différents types de déclaration d'importation;   lorsque vous utilisez "import spam.ham.eggs", le   le spam de package de niveau supérieur doit être placé   dans l'espace de noms d'importation, mais quand   en utilisant "à partir de spam.ham importer des oeufs", le   Le sous-paquet spam.ham doit être utilisé pour   trouver la variable oeufs. Comme un   solution de contournement pour ce comportement, utilisez   getattr () pour extraire le   Composants. Par exemple, vous pourriez   définir l'assistant suivant:

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

Pour paraphraser:

Lorsque vous demandez somepackage.somemodule , __ import __ renvoie somepackage .__ init __. py , qui est souvent vide.

Il retournera somemodule si vous fournissez fromlist (liste des noms de variables à l'intérieur de somemodule que vous souhaitez, qui ne sont pas réellement renvoyés).

Vous pouvez également, comme je l'ai fait, utiliser la fonction proposée.

Remarque: j’ai posé cette question dans l’intention de répondre moi-même. Il y avait un gros problème dans mon code, et après l'avoir mal diagnostiqué, il m'a fallu beaucoup de temps pour le comprendre. J'ai donc décidé d'aider la communauté SO et de poster le piège que j'ai rencontré ici.

Autres conseils

python 2.7 contient importlib, les chemins en pointillés sont résolus comme prévu

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

Il existe une solution plus simple, comme expliqué dans la documentation:

Si vous souhaitez simplement importer un module (éventuellement dans un package) par son nom, vous pouvez appeler __import __ () puis le rechercher dans sys.modules:

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

Quelque chose fonctionne comme vous le souhaitez: 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'>

Pour Python 2.6, j'ai écrit cet extrait:

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

Ce que j'ai fait est

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

alors je peux accéder à tout contenu de par

foobar.functionName()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top