Ich bekomme also diesen Fehler
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
und Sie können sehen, dass ich die gleiche Importanweisung weiter oben verwende und es funktioniert? Gibt es eine ungeschriebene Regel für den zirkulären Import? Wie verwende ich dieselbe Klasse weiter unten im Aufrufstapel?
from
Syntax immer funktioniert. Wenn ichclass A(object): pass; class C(b.B): pass
in Modul a undclass B(a.A): pass
in Modul b habe, ist der zirkuläre Import immer noch ein Problem und dies wird nicht funktionieren.B
in das Modula
oder die KlasseC
in das Modul,b
damit Sie den Zyklus unterbrechen können. Es ist auch erwähnenswert, dass selbst wenn nur eine Richtung des Kreises Code der obersten Ebene enthält (z. B. wennC
keine Klasse vorhanden ist), möglicherweise eine Fehlermeldung angezeigt wird, je nachdem, welches Modul zuerst von einem anderen Code importiert wurde.from . import sibling_module
nichtfrom .sibling_module import SomeClass
). Es gibt etwas mehr Subtilität, wenn die__init__.py
Datei eines Pakets am zirkulären Import beteiligt ist, aber das Problem ist sowohl selten als auch wahrscheinlich ein Fehler in derimport
Implementierung. Siehe Python-Fehler 23447 , für den ich einen Patch eingereicht habe (der leider gelitten hat).Wenn Sie ein Modul (oder ein Mitglied davon) zum ersten Mal importieren, wird der Code im Modul wie jeder andere Code nacheinander ausgeführt. zB wird es nicht anders behandelt als der Körper einer Funktion. Ein
import
nur ein Befehl wie jede andere (Zuordnung, ein Funktionsaufruf,def
,class
). Angenommen, Ihre Importe finden oben im Skript statt, dann passiert Folgendes:World
aus zu importierenworld
, wird dasworld
Skript ausgeführt.world
Skript wird importiertField
, wodurch dasentities.field
Skript ausgeführt wird.entities.post
Skript erreichen, weil Sie versucht haben, es zu importierenPost
entities.post
Skript bewirkt, dass dasphysics
Modul ausgeführt wird, weil es versucht zu importierenPostBody
physics
versucht,Post
aus zu importierenentities.post
entities.post
Modul noch im Speicher vorhanden ist, aber es spielt wirklich keine Rolle. Entweder befindet sich das Modul nicht im Speicher, oder das Modul hat noch keinPost
Mitglied, da die Ausführung der Definition noch nicht abgeschlossen istPost
Post
nicht importiert werden kannAlso nein, es ist nicht "weiter oben im Aufrufstapel". Dies ist eine Stapelverfolgung, in der der Fehler aufgetreten ist. Dies bedeutet, dass beim Import
Post
in diese Klasse ein Fehler aufgetreten ist . Sie sollten keine zirkulären Importe verwenden. Bestenfalls hat es einen vernachlässigbaren Nutzen (normalerweise keinen Nutzen) und verursacht solche Probleme. Es belastet jeden Entwickler, der es wartet, und zwingt ihn, auf Eierschalen zu laufen, um ein Zerbrechen zu vermeiden. Überarbeiten Sie Ihre Modulorganisation.quelle
isinstance(userData, Post)
. Unabhängig davon haben Sie keine Wahl. Der zirkuläre Import funktioniert nicht. Die Tatsache, dass Sie zirkuläre Importe haben, ist für mich ein Codegeruch. Es wird vorgeschlagen, dass Sie einige Funktionen haben, die auf ein drittes Modul verschoben werden sollten. Ich konnte nicht sagen, was, ohne beide Klassen zu betrachten.def
wird erst ausgeführt, wenn die Funktion aufgerufen wird. Der Import erfolgt also erst, wenn Sie die Funktion tatsächlich aufgerufen haben. Bis dahin sollte dasimport
s funktionieren, da eines der Module vor dem Aufruf vollständig importiert worden wäre. Das ist ein absolut widerlicher Hack, und er sollte nicht für längere Zeit in Ihrer Codebasis verbleiben.import foo
und nichtfrom foo import Bar
. Das liegt daran, dass die meisten Module nur Dinge definieren (wie Funktionen und Klassen), die später ausgeführt werden. Module, die beim Importieren wichtige Aufgaben ausführen (z. B. ein Skript, das nicht durch geschützt istif __name__ == "__main__"
), sind möglicherweise immer noch problematisch, aber das ist nicht allzu häufig.Um zirkuläre Abhängigkeiten zu verstehen, müssen Sie sich daran erinnern, dass Python im Wesentlichen eine Skriptsprache ist. Die Ausführung von Anweisungen außerhalb von Methoden erfolgt zur Kompilierungszeit. Importanweisungen werden wie Methodenaufrufe ausgeführt. Um sie zu verstehen, sollten Sie sie wie Methodenaufrufe betrachten.
Wenn Sie einen Import durchführen, hängt das davon ab, ob die zu importierende Datei bereits in der Modultabelle vorhanden ist. In diesem Fall verwendet Python alles, was derzeit in der Symboltabelle enthalten ist. Wenn nicht, beginnt Python mit dem Lesen der Moduldatei und kompiliert / führt / importiert alles, was dort gefunden wird. Symbole, auf die beim Kompilieren verwiesen wird, werden gefunden oder nicht, je nachdem, ob sie vom Compiler gesehen wurden oder noch nicht gesehen wurden.
Stellen Sie sich vor, Sie haben zwei Quelldateien:
Datei X.py.
Datei Y.py.
Angenommen, Sie kompilieren die Datei X.py. Der Compiler definiert zunächst die Methode X1 und trifft dann die Importanweisung in X.py. Dies führt dazu, dass der Compiler die Kompilierung von X.py unterbricht und mit dem Kompilieren von Y.py beginnt. Kurz danach trifft der Compiler die Importanweisung in Y.py. Da X.py bereits in der Modultabelle enthalten ist, verwendet Python die vorhandene unvollständige X.py-Symboltabelle, um alle angeforderten Referenzen zu erfüllen. Alle Symbole, die vor der import-Anweisung in X.py erscheinen, befinden sich jetzt in der Symboltabelle, alle Symbole danach jedoch nicht. Da X1 jetzt vor der Importanweisung angezeigt wird, wurde es erfolgreich importiert. Python setzt dann das Kompilieren von Y.py fort. Dabei wird Y2 definiert und das Kompilieren von Y.py abgeschlossen. Anschließend wird die Kompilierung von X.py fortgesetzt und Y2 in der Y.py-Symboltabelle gefunden. Die Kompilierung wird schließlich ohne Fehler abgeschlossen.
Etwas ganz anderes passiert, wenn Sie versuchen, Y.py über die Befehlszeile zu kompilieren. Beim Kompilieren von Y.py trifft der Compiler die Importanweisung, bevor er Y2 definiert. Dann beginnt es mit dem Kompilieren von X.py. Bald trifft es die Import-Anweisung in X.py, die Y2 erfordert. Y2 ist jedoch undefiniert, sodass die Kompilierung fehlschlägt.
Beachten Sie, dass die Kompilierung immer erfolgreich ist, wenn Sie X.py so ändern, dass Y1 importiert wird, unabhängig davon, welche Datei Sie kompilieren. Wenn Sie jedoch die Datei Y.py so ändern, dass das Symbol X2 importiert wird, wird keine der Dateien kompiliert.
Verwenden Sie NICHT, wenn Modul X oder ein von X importiertes Modul das aktuelle Modul importiert:
Jedes Mal, wenn Sie glauben, dass es zu einem zirkulären Import kommen könnte, sollten Sie auch vermeiden, Verweise auf Variablen in anderen Modulen zu kompilieren. Betrachten Sie den unschuldig aussehenden Code:
Angenommen, Modul X importiert dieses Modul, bevor dieses Modul X importiert. Angenommen, Y wird nach der Importanweisung in X definiert. Dann wird Y nicht definiert, wenn dieses Modul importiert wird, und Sie erhalten einen Kompilierungsfehler. Wenn dieses Modul zuerst Y importiert, können Sie damit durchkommen. Wenn jedoch einer Ihrer Mitarbeiter die Reihenfolge der Definitionen in einem dritten Modul unschuldig ändert, wird der Code unterbrochen.
In einigen Fällen können Sie zirkuläre Abhängigkeiten auflösen, indem Sie eine Importanweisung unter die Symboldefinitionen verschieben, die von anderen Modulen benötigt werden. In den obigen Beispielen schlagen Definitionen vor der Importanweisung niemals fehl. Definitionen nach der import-Anweisung schlagen je nach Kompilierungsreihenfolge manchmal fehl. Sie können sogar Importanweisungen am Ende einer Datei einfügen, sofern beim Kompilieren keines der importierten Symbole benötigt wird.
Beachten Sie, dass das Verschieben von Importanweisungen in einem Modul Ihre Arbeit verdeckt. Kompensieren Sie dies mit einem Kommentar oben in Ihrem Modul wie folgt:
Im Allgemeinen ist dies eine schlechte Praxis, aber manchmal ist es schwer zu vermeiden.
quelle
Für diejenigen unter Ihnen, die wie ich aus Django zu diesem Problem kommen, sollten Sie wissen, dass die Dokumente eine Lösung bieten: https://docs.djangoproject.com/de/1.10/ref/models/fields/#foreignkey
"... Um auf Modelle zu verweisen, die in einer anderen Anwendung definiert sind, können Sie explizit ein Modell mit der vollständigen Anwendungsbezeichnung angeben. Wenn beispielsweise das obige Herstellermodell in einer anderen Anwendung namens Produktion definiert ist, müssen Sie Folgendes verwenden:
Diese Art von Referenz kann nützlich sein, wenn zirkuläre Importabhängigkeiten zwischen zwei Anwendungen aufgelöst werden. ... "
quelle
Wenn Sie in einer recht komplexen App auf dieses Problem stoßen, kann es umständlich sein, alle Ihre Importe zu überarbeiten. PyCharm bietet hierfür einen Quickfix an, der automatisch auch die Verwendung der importierten Symbole ändert.
quelle
Ich konnte das Modul innerhalb der Funktion (nur) importieren, für die die Objekte aus diesem Modul erforderlich sind:
quelle
Ich habe folgendes verwendet:
aber um loszuwerden, habe
circular reference
ich folgendes getan und es hat funktioniert:quelle