Donc j'obtiens cette erreur
Traceback (most recent call last):
File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module>
from world import World
File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in <module>
from entities.field import Field
File "/Users/alex/dev/runswift/utils/sim2014/entities/field.py", line 2, in <module>
from entities.goal import Goal
File "/Users/alex/dev/runswift/utils/sim2014/entities/goal.py", line 2, in <module>
from entities.post import Post
File "/Users/alex/dev/runswift/utils/sim2014/entities/post.py", line 4, in <module>
from physics import PostBody
File "/Users/alex/dev/runswift/utils/sim2014/physics.py", line 21, in <module>
from entities.post import Post
ImportError: cannot import name Post
et vous pouvez voir que j'utilise la même instruction d'importation plus haut et que cela fonctionne? Existe-t-il une règle non écrite concernant l'importation circulaire? Comment utiliser la même classe plus bas dans la pile d'appels?
from
syntaxe fonctionnera toujours. Si j'aiclass A(object): pass; class C(b.B): pass
dans le module a etclass B(a.A): pass
dans le module b, l'importation circulaire est toujours un problème et cela ne fonctionnera pas.B
dans le modulea
ou déplacez la classeC
dans le moduleb
afin de pouvoir interrompre le cycle. Il est également intéressant de noter que même si une seule direction du cercle a un code de premier niveau impliqué (par exemple, si la classeC
n'existait pas), vous pourriez obtenir une erreur, en fonction du module importé en premier par un autre code.from . import sibling_module
, pasfrom .sibling_module import SomeClass
). Il y a plus de subtilité lorsque le__init__.py
fichier d' un package est impliqué dans l'importation circulaire, mais le problème est à la fois rare et probablement un bogue dans l'import
implémentation. Voir le bogue Python 23447 , pour lequel j'ai soumis un correctif (qui, hélas, languit).Lorsque vous importez un module (ou un membre de celui-ci) pour la première fois, le code à l'intérieur du module est exécuté séquentiellement comme tout autre code; par exemple, il n'est pas traité différemment du corps d'une fonction. Un
import
est juste une commande comme une autre (affectation, un appel de fonction,def
,class
). En supposant que vos importations se produisent en haut du script, voici ce qui se passe:World
depuisworld
, leworld
script est exécuté.world
script est importéField
, ce qui entraîne l'entities.field
exécution du script.entities.post
script car vous avez essayé d'importerPost
entities.post
script provoquephysics
l'exécution du module car il tente d'importerPostBody
physics
essaie d'importerPost
depuisentities.post
entities.post
module existe encore en mémoire, mais cela n'a vraiment pas d'importance. Soit le module n'est pas en mémoire, soit le module n'a pas encore dePost
membre car il n'a pas fini de s'exécuter pour définirPost
Post
n'est pas là pour être importéDonc non, ce n'est pas "travailler plus haut dans la pile d'appels". Il s'agit d'une trace de pile de l'endroit où l'erreur s'est produite, ce qui signifie qu'elle a tenté d'importer
Post
dans cette classe. Vous ne devez pas utiliser d'importations circulaires. Au mieux, il a des avantages négligeables (généralement aucun avantage), et cela cause des problèmes comme celui-ci. Cela pèse sur tout développeur qui l'entretient, les obligeant à marcher sur des coquilles d'œufs pour éviter de les casser. Refactorisez l'organisation de vos modules.la source
isinstance(userData, Post)
. Quoi qu'il en soit, vous n'avez pas le choix. L'import circulaire ne fonctionnera pas. Le fait que vous ayez des importations circulaires est une odeur de code pour moi. Cela suggère que vous avez certaines fonctionnalités qui devraient être déplacées vers un troisième module. Je ne pourrais pas dire quoi sans regarder les deux classes entières.def
n'est pas exécuté tant que la fonction n'est pas appelée, de sorte que l'importation ne se produira pas tant que vous n'aurez pas appelé la fonction. D'ici là, leimport
s devrait fonctionner car l'un des modules aurait été complètement importé avant l'appel. C'est un hack absolument dégoûtant, et il ne devrait pas rester dans votre base de code pendant une période de temps significative.import foo
plutôt quefrom foo import Bar
. C'est parce que la plupart des modules définissent simplement des éléments (comme des fonctions et des classes) qui s'exécutent plus tard. Les modules qui font des choses importantes lorsque vous les importez (comme un script non protégé parif __name__ == "__main__"
) peuvent toujours poser problème, mais ce n'est pas trop courant.Pour comprendre les dépendances circulaires, vous devez vous rappeler que Python est essentiellement un langage de script. L'exécution d'instructions en dehors des méthodes se produit au moment de la compilation. Les instructions d'importation sont exécutées comme les appels de méthode, et pour les comprendre, vous devez les considérer comme des appels de méthode.
Lorsque vous effectuez une importation, ce qui se passe dépend du fait que le fichier que vous importez existe déjà dans la table des modules. Si c'est le cas, Python utilise ce qui se trouve actuellement dans la table des symboles. Sinon, Python commence à lire le fichier du module, compilant / exécutant / important tout ce qu'il y trouve. Les symboles référencés au moment de la compilation sont trouvés ou non, selon qu'ils ont été vus ou ne sont pas encore vus par le compilateur.
Imaginez que vous avez deux fichiers source:
Fichier X.py
Fichier Y.py
Supposons maintenant que vous compiliez le fichier X.py. Le compilateur commence par définir la méthode X1, puis accède à l'instruction d'importation dans X.py. Cela oblige le compilateur à suspendre la compilation de X.py et à commencer la compilation de Y.py. Peu de temps après, le compilateur accède à l'instruction d'importation dans Y.py. Puisque X.py est déjà dans la table des modules, Python utilise la table des symboles X.py incomplète existante pour satisfaire toutes les références demandées. Tous les symboles apparaissant avant l'instruction d'importation dans X.py sont maintenant dans la table des symboles, mais les symboles après ne le sont pas. Puisque X1 apparaît maintenant avant l'instruction d'importation, il est importé avec succès. Python reprend ensuite la compilation de Y.py. Ce faisant, il définit Y2 et termine la compilation de Y.py. Il reprend ensuite la compilation de X.py et trouve Y2 dans la table des symboles Y.py. La compilation se termine finalement sans erreur.
Quelque chose de très différent se produit si vous essayez de compiler Y.py à partir de la ligne de commande. Lors de la compilation de Y.py, le compilateur accède à l'instruction d'importation avant de définir Y2. Ensuite, il commence à compiler X.py. Bientôt, il atteint l'instruction d'importation dans X.py qui nécessite Y2. Mais Y2 n'est pas défini, donc la compilation échoue.
Veuillez noter que si vous modifiez X.py pour importer Y1, la compilation réussira toujours, quel que soit le fichier que vous compilez. Cependant, si vous modifiez le fichier Y.py pour importer le symbole X2, aucun des fichiers ne sera compilé.
À tout moment où le module X, ou tout module importé par X peut importer le module actuel, n'utilisez PAS:
Chaque fois que vous pensez qu'il peut y avoir une importation circulaire, vous devez également éviter les références de compilation à des variables dans d'autres modules. Considérez le code à l'air innocent:
Supposons que le module X importe ce module avant que ce module importe X. Supposons en outre que Y est défini dans X après l'instruction d'importation. Ensuite, Y ne sera pas défini lors de l'importation de ce module et vous obtiendrez une erreur de compilation. Si ce module importe d'abord Y, vous pouvez vous en tirer. Mais lorsqu'un de vos collègues change innocemment l'ordre des définitions dans un troisième module, le code se cassera.
Dans certains cas, vous pouvez résoudre les dépendances circulaires en déplaçant une instruction d'importation vers le bas sous les définitions de symboles requises par d'autres modules. Dans les exemples ci-dessus, les définitions avant l'instruction import n'échouent jamais. Les définitions après l'instruction d'importation échouent parfois, selon l'ordre de compilation. Vous pouvez même placer des instructions d'importation à la fin d'un fichier, à condition qu'aucun des symboles importés ne soit nécessaire au moment de la compilation.
Notez que déplacer les instructions d'importation vers le bas dans un module obscurcit ce que vous faites. Compensez cela avec un commentaire en haut de votre module, quelque chose comme ce qui suit:
En général, c'est une mauvaise pratique, mais parfois difficile à éviter.
la source
Pour ceux d'entre vous qui, comme moi, abordez ce problème depuis Django, sachez que la documentation fournit une solution: https://docs.djangoproject.com/en/1.10/ref/models/fields/#foreignkey
"... Pour faire référence à des modèles définis dans une autre application, vous pouvez spécifier explicitement un modèle avec l'étiquette d'application complète. Par exemple, si le modèle Fabricant ci-dessus est défini dans une autre application appelée production, vous devez utiliser:
Ce type de référence peut être utile lors de la résolution des dépendances d'importation circulaire entre deux applications. ... "
la source
J'ai pu importer le module dans la fonction (uniquement) qui nécessiterait les objets de ce module:
la source
Si vous rencontrez ce problème dans une application assez complexe, il peut être fastidieux de refactoriser toutes vos importations. PyCharm propose un correctif rapide pour cela qui modifiera automatiquement toutes les utilisations des symboles importés.
la source
J'utilisais ce qui suit:
mais pour
circular reference
m'en débarrasser, j'ai fait ce qui suit et cela a fonctionné:la source