2017-07-10 5 views
0

Désolé pour le titre confus, laissez-moi vous expliquer ce que je veux dire. Je suis tombé sur un morceau de code similaire à celui qui suit en utilisant PrettyTensor API de Google, où il permet d'ajouter des fonctions personnalisées à la classe PrettyTensor grâce à son décorateur @ prettytensor.Register().Pourquoi les modules Python modifiés lors de l'exécution sont-ils conservés sur des fichiers séparés?

(situé dans custom_ops.py)

import prettytensor as pt 

@pt.Register(...) 
def custom_foo(bar): 
    ... 

(situé dans main.py)

import prettytensor as pt 
import custom_ops 

x = pt.custom_foo(bar) 

Ce code accède prettytensor par 2 fichiers séparés, et je ne comprends pas pourquoi les changements fait dans un fichier report à l'autre. Ce qui est également intéressant, c'est que l'ordre des importations n'a pas d'importance.

import custom_ops 
import prettytensor as pt 

x = pt.custom_foo(bar) 

Le code ci-dessus fonctionne toujours correctement. J'aimerais avoir de l'aide pour trouver une explication à ce phénomène, car je n'ai trouvé nulle part de documentation à ce sujet. Il me semble que l'interpréteur python cache le module en mémoire, et lorsqu'il est modifié par le fichier custom_ops, il persiste dans l'interpréteur lorsqu'il est à nouveau importé. Si quelqu'un sait pourquoi cela arrive, comment l'empêcheriez-vous?

+0

Je suis désolé, je ne comprends pas votre question. Quel est exactement le comportement inattendu? –

+6

modules sont stockés globalement dans 'sys.modules', les imports dans des modules séparés se réfèrent identiquement au même objet module et donc les modifications sont persistantes –

+2

@AnthonySottile oui, pour ajouter à cela, il n'est pas utile de considérer les modules comme des" fichiers " ". Les fichiers sont le code source qui, lorsqu'il est exécuté, crée des objets-modules.Ces objets existent en mémoire, pas dans les fichiers '.py'. –

Répondre

1

La raison pour laquelle vos deux modules voient la même version du module prettytensor est que Python met en cache les objets de module qu'il crée lorsqu'il charge un module pour la première fois. Le même objet module module peut ensuite être importé autant de fois qu'il le faut à différents endroits (ou même plusieurs fois dans le même module, si vous avez une raison de le faire), sans être rechargé depuis son fichier.

Vous pouvez voir tous les modules qui ont été chargés dans le dictionnaire sys.modules. Chaque fois que vous effectuez un import d'un module qui a déjà été chargé, Python le verra dans sys.modules et vous obtiendrez une référence à l'objet module qui existe déjà à la place d'un nouveau module chargé à partir du fichier .py.

En général, c'est ce que vous voulez. C'est généralement une très mauvaise chose si deux parties différentes du code peuvent obtenir une référence à un module chargé à partir du même fichier via deux noms de modules différents. Par exemple, vous pouvez avoir deux objets qui prétendent tous deux être des instances de la classe foo.Foo, mais ils peuvent être des instances de deux différentes classesfoo.Foo si vous pouvez accéder à foo de deux manières différentes. Cela peut faire du débogage un véritable cauchemar.

Des modules dupliqués peuvent se produire si votre chemin de recherche de module Python est fautif (de sorte que les modules à l'intérieur d'un paquet soient également exposés au niveau supérieur). Cela peut également se produire avec le module __main__ (créé à partir du fichier que vous exécutez en tant que script), qui peut également être importé en utilisant son nom normal (par exemple main dans votre exemple avec main.py).

Vous pouvez également recharger manuellement un module à l'aide de la fonction reload. En Python 2 c'était un builtin, mais il est caché dans importlib maintenant en Python 3.

+0

Merci! Cela aide beaucoup! – TheCoolManz