Was passiert, wenn sich zwei Module gegenseitig importieren?
Was ist mit den zyklischen Importen in Python, um das Problem zu verallgemeinern?
Was passiert, wenn sich zwei Module gegenseitig importieren?
Was ist mit den zyklischen Importen in Python, um das Problem zu verallgemeinern?
Antworten:
Letztes Jahr gab es auf comp.lang.python eine wirklich gute Diskussion darüber . Es beantwortet Ihre Frage ziemlich gründlich.
quelle
Wenn Sie
import foo
innenbar
undimport bar
innen tunfoo
, wird es gut funktionieren. Wenn tatsächlich etwas ausgeführt wird, sind beide Module vollständig geladen und haben Verweise aufeinander.Das Problem ist, wenn Sie stattdessen
from foo import abc
undfrom bar import xyz
. Denn jetzt muss für jedes Modul das andere Modul bereits importiert sein (damit der zu importierende Name vorhanden ist), bevor es importiert werden kann.quelle
from foo import *
undfrom bar import *
wird auch gut funktionieren.from x import y
und erhält dennoch den zirkulären Importfehlerimport
Anweisung ausgeführt wird. Es wird also kein Fehler auftreten, aber Sie erhalten möglicherweise nicht alle Variablen, die Sie erwarten.from foo import *
und tunfrom bar import *
, befindet sich alles, was in der ausgeführtfoo
wird, in der Initialisierungsphase vonbar
und die tatsächlichen Funktionen in wurdenbar
noch nicht definiert ...Zyklische Importe werden beendet, Sie müssen jedoch darauf achten, die zyklisch importierten Module während der Modulinitialisierung nicht zu verwenden.
Betrachten Sie die folgenden Dateien:
a.py:
b.py:
Wenn Sie a.py ausführen, erhalten Sie Folgendes:
Beim zweiten Import von b.py (im zweiten
a in
) wird der Python-Interpreter nichtb
erneut importiert , da er bereits im Modul dict vorhanden ist.Wenn Sie versuchen, zuzugreifen
b.x
ausa
während Modulinitialisierung, erhalten Sie einAttributeError
.Fügen Sie die folgende Zeile hinzu
a.py
:Dann ist die Ausgabe:
Dies liegt daran, dass Module beim Import ausgeführt werden und zum Zeitpunkt des
b.x
Zugriffs die Zeilex = 3
noch nicht ausgeführt wurde, was erst danach geschiehtb out
.quelle
__name__
stattdessen verwenden würden'a'
. Am Anfang war ich total verwirrt, warum eine Datei zweimal ausgeführt wird.Wie andere Antworten beschreiben, ist dieses Muster in Python akzeptabel:
Dadurch wird die Ausführung der Importanweisung vermieden, wenn die Datei von anderen Modulen importiert wird. Nur wenn eine logische zirkuläre Abhängigkeit besteht, schlägt dies fehl.
Die meisten Zirkularimporte sind keine logischen Zirkularimporte, sondern verursachen
ImportError
Fehler, daimport()
beim Aufruf Anweisungen der obersten Ebene der gesamten Datei ausgewertet werden.Diese
ImportErrors
können fast immer vermieden werden, wenn Sie Ihre Importe ganz oben haben möchten :Betrachten Sie diesen zirkulären Import:
App A.
App B.
Von David Beazleys exzellenten Vortragsmodulen und -paketen: Live and Let Die! - PyCon 2015 ,
1:54:00
hier ist eine Möglichkeit, mit zirkulären Importen in Python umzugehen:Dies versucht zu importieren
SimplifiedImageSerializer
und wennImportError
es ausgelöst wird, weil es bereits importiert ist, wird es aus dem Importcache gezogen.PS: Sie müssen diesen gesamten Beitrag in David Beazleys Stimme lesen.
quelle
Ich habe hier ein Beispiel, das mich beeindruckt hat!
foo.py.
bar.py.
main.py.
In der Befehlszeile: $ python main.py
quelle
import bar
infoo.py
bis zum Endebar
undfoo
beide verwenden müssengX
, besteht die "sauberste" Lösung darin,gX
ein anderes Modul einzubauen und beide zu habenfoo
undbar
dieses Modul zu importieren. (Am saubersten in dem Sinne, dass es keine versteckten semantischen Abhängigkeiten gibt.)bar
ich nicht einmalgX
im Foo finden kann. Der zirkuläre Import ist an sich in Ordnung, aber es ist nur so, dassgX
er beim Import nicht definiert wird.Modul a.py:
Modul b.py.
Wenn Sie "Modul a" ausführen, wird Folgendes ausgegeben:
Es gab diese 3 Zeilen aus, während es wegen des zirkulären Imports Infinitiv ausgeben sollte. Was beim Ausführen von "Modul a" Zeile für Zeile passiert, ist hier aufgeführt:
import b
. so wird es Modul b besuchenimport a
. so wird es Modul a besuchenimport b
aber beachten Sie, dass diese Zeile nicht mehr erneut ausgeführt wird , da jede Datei in Python eine Importzeile nur einmal ausführt. Es spielt keine Rolle, wo oder wann sie ausgeführt wird. so wird es zur nächsten Zeile übergehen und drucken"This is from module a"
."This is from module b"
"This is from module a"
und das Programm wird beendet.quelle
Ich stimme der Antwort von Python hier voll und ganz zu. Ich bin jedoch auf Code gestoßen, der bei zirkulären Importen fehlerhaft war und Probleme beim Hinzufügen von Komponententests verursachte. Um es schnell zu patchen, ohne alles zu ändern, können Sie das Problem durch einen dynamischen Import beheben.
Auch dies ist keine dauerhafte Korrektur, kann aber jemandem helfen, der einen Importfehler beheben möchte, ohne zu viel Code zu ändern.
Prost!
quelle
Hier gibt es viele gute Antworten. Während es normalerweise schnelle Lösungen für das Problem gibt, von denen sich einige pythonischer anfühlen als andere, besteht ein anderer Ansatz darin, die Organisation Ihres Codes zu analysieren und zu versuchen, die zirkuläre Abhängigkeit zu beseitigen, wenn Sie den Luxus haben, Refactoring durchzuführen. Sie können zum Beispiel feststellen, dass Sie:
Datei a.py.
Datei b.py.
In diesem Fall wird nur eine statische Methode in einer separaten Datei zu bewegen, sagen
c.py
:Datei c.py.
ermöglicht das Entfernen der
save_result
Methode aus A und damit das Entfernen des Imports von A aus a in b:Refactored File a.py.
Refactored File b.py.
Wenn Sie ein Tool (z. B. Pylint oder PyCharm) haben, das über statische Methoden berichtet, ist es
staticmethod
möglicherweise nicht die beste Möglichkeit, die Warnung auszuschalten, wenn Sie nur einen Dekorator darauf werfen . Obwohl die Methode mit der Klasse verwandt zu sein scheint, ist es möglicherweise besser, sie zu trennen, insbesondere wenn Sie mehrere eng verwandte Module haben, die möglicherweise dieselbe Funktionalität benötigen, und Sie beabsichtigen, DRY-Prinzipien zu üben.quelle
Zirkuläre Importe können verwirrend sein, da der Import zwei Dinge bewirkt:
Ersteres wird nur einmal durchgeführt, letzteres bei jeder Importanweisung. Der zirkuläre Import schafft eine Situation, wenn beim Importieren eines Moduls ein importiertes Modul mit teilweise ausgeführtem Code verwendet wird. Infolgedessen werden keine Objekte angezeigt, die nach der Importanweisung erstellt wurden. Das folgende Codebeispiel zeigt dies.
Zirkuläre Importe sind nicht das ultimative Übel, das um jeden Preis vermieden werden muss. In einigen Frameworks wie Flask sind sie ganz natürlich, und wenn Sie Ihren Code optimieren, um sie zu entfernen, wird der Code nicht besser.
main.py.
b.by.
a.py.
python main.py Ausgabe mit Kommentaren
quelle
Ich habe das Problem folgendermaßen gelöst und es funktioniert ohne Fehler. Betrachten Sie zwei Dateien
a.py
undb.py
.Ich habe das hinzugefügt
a.py
und es hat funktioniert.a.py:
b.py:
Die Ausgabe, die ich bekomme, ist
quelle
Ok, ich denke ich habe eine ziemlich coole Lösung. Angenommen, Sie haben Datei
a
und Dateib
. Sie haben einedef
oder eineclass
in der Datei ,b
die Sie in Modul verwenden möchtena
, aber Sie haben etwas anderes, entweder eindef
,class
oder eine Variable aus der Datei ,a
die Sie in Ihrer Definition oder Klasse in der Datei benötigenb
. Was Sie tun können, ist am Ende der Dateia
, nachdem Sie die Funktion oder Klasse in der Datei aufgerufen habena
, die in der Datei benötigt wirdb
, aber bevor Sie die Funktion oder Klasse aus der Datei aufrufen, dieb
Sie für die Datei benötigena
, sagen Sieimport b
Dann, und hier ist der Schlüsselteil , in allen Definitionen oder Klassen in der Dateib
, die dasdef
oder benötigenclass
Datei vona
(nennen wir esCLASS
), sagst dufrom a import CLASS
Dies funktioniert, weil Sie Dateien importieren können,
b
ohne dass Python eine der Importanweisungen in der Datei ausführtb
, und sich somit jeglichen zirkulären Importen entziehen.Zum Beispiel:
Datei A:
Datei b:
Voila.
quelle
from a import CLASS
überspringt nicht die Ausführung des gesamten Codes in a.py. Dies ist, was wirklich passiert: (1) Der gesamte Code in a.py wird als spezielles Modul "__main__" ausgeführt. (2) Umimport b
wird der Code der obersten Ebene in b.py ausgeführt (Definition der Klasse B) und die Steuerung kehrt zu "__main__" zurück. (3) "__main__" übergibt schließlich die Kontrolle ango.dostuff()
. (4) Wenn dostuff () zu kommtimport a
, läuft es den gesamten Code in a.py erneut , diesmal als das Modul „a“; dann importiert es das CLASS-Objekt aus dem neuen Modul "a". Eigentlich würde dies genauso gut funktionieren, wenn Sieimport a
irgendwo in b.py verwenden würden.