3 votes

Pourquoi ne peut-on pas ré-importer en Python?

Il y a beaucoup de questions et de réponses concernant les ré-importations sur SO, mais tout semble très contre-intuitif sans connaître les mécanismes derrière.

Si vous importez un module, changez le contenu, puis essayez de l'importer à nouveau, vous constaterez que le deuxième import n'a aucun effet :

>>> import foo    # foo.py contient : bar = 'original'
>>> print foo.bar
original
>>> # editer foo.py et changer pour : bar = 'changed'
>>> import foo
>>> print foo.bar
original

J'étais un campeur très heureux quand j'ai découvert reload :

>>> reload(foo)
>>> print foo.bar
changed

Cependant, il n'y a pas de solution facile lorsque vous importez des éléments d'un module sans importer le module lui-même :

>>> from foo import baz
>>> print baz
original
>>> # changer foo.py de baz = 'original' à baz = 'changed'
>>> from foo import baz
>>> print baz
original
>>> reload(foo)
Traceback (most recent call last):
  File "", line 1, in 
    reload(foo)
NameError: name 'foo' not defined

Pourquoi Python ne met-il pas à jour les éléments importés lorsque vous lui donnez une nouvelle instruction import ?

11voto

Mark Ransom Points 132545

Lorsque vous importez un module, il est mis en cache dans sys.modules. Toute tentative d'importer le même module à nouveau au sein de la même session renvoie simplement le module déjà existant qui s'y trouve. Cela accélère l'expérience globale lorsque un module est importé à partir de plusieurs endroits. Cela permet également à un module d'avoir ses propres objets partagés entre toutes les importations, car le même module est renvoyé à chaque fois.

Comme mentionné, vous pouvez utiliser reload pour ré-importer un module entier. Consultez la documentation pour les limitations, car même cela n'est pas infaillible.

Lorsque vous importez des éléments spécifiques à partir d'un module, le module entier est importé comme ci-dessus, puis les objets que vous avez demandés sont placés dans votre espace de noms. reload ne fonctionne pas parce que ces objets ne sont pas des modules, et vous n'avez jamais reçu de référence au module lui-même. La solution de contournement est d'obtenir une référence au module, de le recharger, puis de le ré-importer :

>>> from foo import baz
>>> print baz
original
>>> # change foo.py from baz = 'original' to baz = 'changed'
>>> import foo
>>> reload(foo)
>>> from foo import baz
>>> print baz
changed

2voto

BrenBarn Points 63718

La simple explication de "pourquoi" est que les instructions d'importation impliquent deux opérations : charger le module (c'est-à-dire exécuter le code à l'intérieur), et importer les noms dans l'espace de noms du module d'importation. Réimporter ne refait que la deuxième opération. La raison en est que la première opération peut être coûteuse en termes de ressources de calcul et de mémoire.

reload est fourni comme un moyen de refaire la première opération, mais, comme vous l'avez vu, il nécessite le nom du module. Ne vous laissez cependant pas duper en pensant que from foo import bar ne charge pas l'ensemble du module. C'est le cas. Tout le code du module est exécuté, c'est juste que vous ne pouvez vous référer qu'aux noms (par exemple, bar) que vous importez explicitement. Pour cette raison, il y a peu de différence réelle entre importer le module et ne pas l'importer ; les seules différences sont des problèmes d'espace de noms. Donc si vous pensez que vous voudriez recharger le module foo, vous devriez aller de l'avant et faire import foo. Si vous le voulez, vous pouvez le faire pour rafraîchir vos noms importés:

import foo
from foo import bar
# plus tard...
reload(foo)
from foo import bar

Il y a une autre raison pour laquelle vous ne pouvez pas réimporter des noms individuels, qui est que Python n'a aucun moyen de changer les objets auxquels il est fait référence ; il ne peut que réaffecter les noms. Supposez que vous fassiez ceci :

from foo import bar
newBar = bar
from foo import bar

Même si la deuxième importation rafraîchissait vraiment la valeur de bar, elle ne pourrait jamais rafraîchir la valeur de newBar, car ni foo ni bar n'ont aucun moyen de savoir que vous avez créé un nom supplémentaire pour faire référence à bar. Éviter la réaffectation des noms individuels vous empêche de tomber dans ce piège ; si les gens pensaient que la réimportation rafraîchirait les noms, il serait facile d'oublier que cela ne rafraîchirait toujours pas les objets.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X