2008-10-17 7 views

Répondre

52

De la documentation python sur __import__:

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

...

Lorsque la variable nom est de la forme package.module, normalement, le paquet de haut niveau (la nom jusqu'à le premier point) est renvoyé, pas le module nommé par son nom. Cependant, lorsqu'un argument non vide de liste est donné, le module nommé par son nom est renvoyé. Cela est fait pour la compatibilité avec le bytecode généré pour les différents types de déclaration d'importation; ; lors de l'utilisation de "import spam.ham.eggs", le spam de niveau supérieur doit être placé dans l'espace de noms d'importation, mais lorsque utilise "from spam.ham import eggs", le sous-paquetage spam.ham doit être utilisé à trouver les oeufs variable. Pour résoudre ce problème, utilisez getattr() pour extraire les composants souhaités. Par exemple, vous pouvez définir l'aide suivante:

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__ retours somepackage.__init__.py, ce qui est souvent vide.

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

Vous pouvez aussi, comme je l'ai fait, utilisez la fonction qu'ils suggèrent.

Note: J'ai posé cette question dans l'intention d'y répondre moi-même. Il y avait un gros bug dans mon code, et après l'avoir mal diagnostiqué, il m'a fallu beaucoup de temps pour le comprendre, donc j'ai pensé que j'aiderais la communauté SO et posterais le gotcha que j'ai rencontré ici.

7

Il y a quelque chose qui fonctionne comme vous voulez à: 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'> 
+0

C'est très utile, mais je n'ai pas vraiment tout autre besoin de tordu dans mon programme. Bien que, en tant que fondateur (!), Vous êtes probablement plus au courant des possibilités que moi (jamais utilisé). – dwestbrook

32

Python 2.7 a importlib, chemins pointillées résoudre comme prévu

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

Il y a aussi un paquet python 2.6 qui supporte cette fonctionnalité. https://pypi.python.org/pypi/importlib/ – melinath

1

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 
16

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

Si vous souhaitez simplement importer un module (potentiellement 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 ...> 
0

La façon dont je l'ai fait est

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

alors je peux accéder à tout contenu par

foobar.functionName() 
+1

Pourquoi pas juste, 'foo.bar' à ce moment-là? –

Questions connexes