2010-09-19 5 views
3

Je me demandais juste pourquoi __import__() appelle deux fois un module __init__ lors du chargement d'un paquet.__import __() appelle __init__.py deux fois?

test.py 
testpkg/ 
     __init__.py 

test.py:

pkg = __import__("testpkg", fromlist=['']) 

__init__.py:

print "Called." 

Après avoir appelé python test.py, appelé. seront imprimés deux fois. Pourquoi python exécute-t-il deux fois le "module" __init__?

+0

Je ne peux pas reproduire ce comportement sur Python 2.6.5. Quelle version utilisez-vous? Êtes-vous sûr que c'est le code complet que vous avez posté là-bas? –

+0

J'utilise Python 2.6.4. Les deux lignes de code sont tout ce que j'utilise pour reproduire. Je viens d'essayer avec Python 2.4.3, j'obtiens les mêmes résultats. –

+0

Je l'ai sur python 2.6.5 sur linux2 construit avec g.c.c 4.4.3 – aaronasterling

Répondre

5

Ceci est un bug Python. Passer la chaîne nulle en tant qu'élément de fromlist est illégal et devrait déclencher une exception. Il n'est pas nécessaire d'inclure "" dans fromlist; c'est implicite - le module lui-même est toujours chargé. Ce qui se passe réellement, c'est que la chaîne module.submodule utilise la chaîne nulle, ce qui donne le nom du module testpkg., avec une période de fin. Cela est importé littéralement, et comme son nom est différent de testpkg, il est importé en tant que module séparé.

Essayez ceci:

pkg = __import__("testpkg", fromlist=['']) 
import sys 
print sys["testpkg"] 
print sys["testpkg."] 

... et vous verrez le module double.

Quelqu'un devrait probablement déposer un ticket s'il n'y en a pas déjà un; trop fatigué pour le faire moi-même en ce moment.

+0

Note: cela se passe pour moi en Python 2.6.4 et 3.1.1.Si vous déposez un bug, assurez-vous qu'il n'est pas déjà corrigé dans les versions les plus récentes. –

+0

il y avait déjà un ticket 2090 pour python 2.7 mais je n'ai vu aucun message des versions mentionnées sur cette page donc j'ai ajouté un commentaire. – aaronasterling

+0

Vous avez raison. Après avoir remplacé [''] par une liste vide, le module '__init__' n'est appelé qu'une seule fois. Juste fixé le SO-Réponse j'ai copié ce code. –

5

L'utilisation du hack fromlist=[''] pour importer un module spécifique est explicitement désapprouvée par python-dev. Bien qu'il ait été filed as an issue, les chances qu'il soit corrigé sont faibles, car cela est considéré comme une mauvaise utilisation de fromlist au lieu d'être nécessairement un bogue et une meilleure solution est disponible. Ce que vous devez faire est d'utiliser importlib.import_module (disponible dans la bibliothèque standard pour Python 2.7 et Python 3.1, ou à partir de PyPI avec la compatibilité vers Python 2.3 en plus d'être inclus dans Django depuis 1.1 comme django.utils.importlib). Cela évitera ce problème, fournira une meilleure interface de programmation pour l'importation de modules et vous permettra même d'utiliser les importations relatives lorsque vous spécifiez le paquet à partir duquel vous importez.

Si vous vraiment ne pouvez pas utiliser importlib (par exemple, les dépendances PyPI ne sont pas autorisés, même si le code que vous pouvez copier librement grâce à la licence de PSF et qu'il soit assez court), alors vous devriez faire __import__("some.module"); mod = sys.modules["some.module"]. C'est la solution officielle sanctionnée par python-dev au problème (mais seulement après vous ne pouvez pas utiliser importlib).

Questions connexes