Was kann ich bei “ImportError: Name X kann nicht importiert werden” oder “AttributeError: … (höchstwahrscheinlich aufgrund eines zirkulären Imports)” tun?
Lesezeit: 7 Minuten
verkauft
Ich habe einen Code, der auf mehrere Dateien verteilt ist, die dies versuchen import voneinander wie folgt:
main.py:
from entity import Ent
Entity.py:
from physics import Physics
class Ent:
...
physik.py:
from entity import Ent
class Physics:
...
Ich laufe dann ab main.py und ich bekomme folgenden Fehler:
Traceback (most recent call last):
File "main.py", line 2, in <module>
from entity import Ent
File ".../entity.py", line 5, in <module>
from physics import Physics
File ".../physics.py", line 2, in <module>
from entity import Ent
ImportError: cannot import name Ent
Ich gehe davon aus, dass der Fehler auf den Import zurückzuführen ist entity zweimal – einmal drin main.py und später rein physics.py – aber wie kann ich das Problem umgehen?
Siehe auch Was passiert bei der Verwendung von gegenseitigen oder kreisförmigen (zyklischen) Importen in Python? für einen allgemeinen Überblick darüber, was erlaubt ist und was ein Problem beim WRT-Zirkularimport verursacht. Siehe Warum funktionieren kreisförmige Importe scheinbar weiter oben in der Aufrufliste, lösen dann aber einen ImportError weiter unten aus? für technische Details auf warum und wie das Problem tritt auf.
In welcher Verzeichnisstruktur werden sie gespeichert und in welchen Verzeichnissen?
– Ben
12. Februar 2012 um 20:56 Uhr
Schauen Sie sich diese Antwort zum Schleifenimport in Python an: stackoverflow.com/questions/7199466/…
– Gregor
12. Februar 2012 um 20:56 Uhr
Im Allgemeinen ist es keine gute Programmierpraxis from <module> import <name>oder from <modlue> import *. Importieren Sie besser unter dem Modulnamensraum, um zu verhindern, dass identisch benannte Referenzen überschrieben werden.
– Joel Cornett
12. Februar 2012 um 20:57 Uhr
@jsells Sie sollten einfach Ihre Klassen anrufen Entity und Vector Anstatt von Ent und Vect, gibt es keinen Grund, solche Namen zu kürzen. Und ja, verwenden import vector und dann x = vector.Vector(0,0,0).
– Benutzer2032433
18. April 2013 um 17:00 Uhr
Hey @Kevin, da du Java besser kennst, was ist dein Eindruck davon Artikel 2008 wobei sich der erste Satz des Autors darauf bezieht, wie zirkuläre Abhängigkeiten sind “ziemlich gängige Praxis” auf Java?
– HeyWatchThis
8. Mai 2014 um 20:52 Uhr
Teemu Ikonen
Sie haben zirkulär abhängige Importe. physics.py importiert wird aus entity vor dem Unterricht Ent definiert ist und physics versucht zu importieren entity das wird schon initialisiert. Entfernen Sie die Abhängigkeit von physics aus entity Modul.
Es gibt nicht viel, was Sie tun können, als Ihren Code umzugestalten. Wenn Sie nicht auf Physik in der Ent-Konstruktordefinition verweisen, verschieben Sie den Import direkt unter die Ent. Fügen Sie in diesem Fall eine Methode wie setPhysics hinzu, um den Import nach dem Konstruktor zu ermöglichen.
– Teemu Ikonen
13. Februar 2012 um 7:22 Uhr
@jsells Da Sie “schon lange” mit C++ arbeiten, sollten Sie wissen, dass zwei Klassen NIEMALS voneinander abhängig sein sollten. Dies ist in C++ äußerst wichtig, und selbst wenn es in Python nicht die Nummer eins ist, ist es dennoch eine wirklich gute Idee, diese Regel zu befolgen. Habe niemals zwei Klassen, die sich kennen, niemals. Wenn Sie Hilfe beim Erstellen der Struktur für Ihre Klassen benötigen, posten Sie auch den Rest des Codes. Wie genau (in Bezug auf Code) sind Entity und Physics miteinander verknüpft? Ich bin sicher, es gibt eine Problemumgehung für das, was Sie versuchen zu tun.
– Benutzer2032433
18. April 2013 um 17:03 Uhr
@ user2032433 Das hängt wirklich davon ab, was Sie mit “einander kennen” meinen. Es ist wahr, dass gutes Design normalerweise einen Baum von Abhängigkeiten in eine Richtung produziert, und dies ist normalerweise der beste Ansatz. Aber es gibt Ausnahmen davon. C++-Klassen können durchaus zirkulär aufeinander verweisen. (Obwohl es unmöglich ist, dass sie aus einander bestehen.) Ohne Vorwärtsdeklaration ist dies ein Problem in Python, für das es nicht immer eine C++-Lösung gibt.
– John McFarlane
3. Juni 2014 um 19:14 Uhr
Die Aussage “Zwei Klassen sollten NIEMALS voneinander abhängig sein” ist Quatsch. Zwei-Wege-Navigation (bidirektional) ist in der Objektorientierung sehr verbreitet. books.google.co.uk/…
– Martin Spamer
17. Dezember 2014 um 17:38 Uhr
Das State-Entwurfsmuster (zum Beispiel) wird normalerweise mit einer Context-Klasse und einer State-Schnittstelle implementiert. State-Instanzen wird die Context-Instanz übergeben, damit sie setState aufrufen können. Dies erfordert, dass der Staat den Kontext kennt und umgekehrt. Inwiefern ist dieses klassische Konstrukt „schlecht im Code“? Eigentlich ist das genau das Problem, mit dem ich in Python kämpfe, aber nicht musste, als ich State in Java implementierte.
– Vorzeichen
1. Dezember 2017 um 20:17 Uhr
Während Sie zirkuläre Abhängigkeiten unbedingt vermeiden sollten, können Sie Importe in Python verschieben.
zum Beispiel:
import SomeModule
def someFunction(arg):
from some.dependency import DependentClass
dies (zumindest in einigen Fällen) wird den Fehler umgehen.
zirkuläre Abhängigkeiten werden am besten umgangen
– kb
8. Juli 2016 um 21:27 Uhr
Basierend auf pep8 ist das Einfügen von import in die Methode keine gute Praxis
– Tom Sawyer
10. Mai 2019 um 17:29 Uhr
@TomSawyer Warum?
– Kröw
3. November 2019 um 7:41 Uhr
@TomSawyer Ich empfehle das nicht, aber es ist eine schnelle Lösung, die Sie aus der Klemme bringen kann
– brüllen
11. Mai 2020 um 21:24 Uhr
@bharling kannst du das etwas näher erklären? Dies war eine starke Lösung für mich
– ergangen
3. Juni um 22:23 Uhr
Dünen
Dies ist eine zirkuläre Abhängigkeit. Es kann ohne strukturelle Änderungen am Code gelöst werden. Das Problem tritt auf, weil in vector das verlangst du entity sofort nutzbar gemacht werden und umgekehrt. Der Grund für dieses Problem ist, dass Sie um Zugriff auf den Inhalt des Moduls bitten, bevor es fertig ist – indem Sie from x import y. Dies ist im Wesentlichen dasselbe wie
import x
y = x.y
del x
Python ist in der Lage, zirkuläre Abhängigkeiten zu erkennen und die Endlosschleife von Importen zu verhindern. Im Grunde wird nur ein leerer Platzhalter für das Modul erstellt (dh es hat keinen Inhalt). Sobald die zirkulär abhängigen Module kompiliert sind, aktualisiert es das importierte Modul. Das funktioniert ungefähr so.
a = module() # import a
# rest of module
a.update_contents(real_a)
Damit Python mit zirkulären Abhängigkeiten arbeiten kann, müssen Sie verwenden import x nur Stil.
import x
class cls:
def __init__(self):
self.y = x.y
Da Sie sich nicht mehr auf den Inhalt des Moduls auf der obersten Ebene beziehen, kann Python das Modul kompilieren, ohne tatsächlich auf den Inhalt der zirkulären Abhängigkeit zugreifen zu müssen. Mit oberster Ebene meine ich Zeilen, die während der Kompilierung ausgeführt werden, im Gegensatz zu den Inhalten von Funktionen (z. y = x.y). Auch statische oder Klassenvariablen, die auf die Modulinhalte zugreifen, verursachen Probleme.
Diese Antwort ist wichtig und eine allgemeinere Lösung für andere. Beachten Sie, dass beim Importieren eines lokalen Submoduls (z import app.foo.bar) müssen Sie ihm einen Namen geben (z import app.foo.bar as bar)
– Datenprinzessin
28. Juli 2020 um 21:48 Uhr
In meinem Fall habe ich in einem Jupyter-Notebook gearbeitet, und dies geschah, weil der Import bereits zwischengespeichert wurde, als ich die Klasse/Funktion in meiner Arbeitsdatei definiert hatte.
Ich habe meinen Jupyter-Kernel neu gestartet und der Fehler ist verschwunden.
Es ist sehr wichtig, die Logik klar zu machen. Dieses Problem tritt auf, weil die Referenz zu einer toten Schleife wird.
Wenn Sie die Logik nicht ändern möchten, können Sie die Import-Anweisung, die ImportError verursacht hat, an einer anderen Position der Datei platzieren, beispielsweise am Ende.
a.py
from test.b import b2
def a1():
print('a1')
b2()
b.py
from test.a import a1
def b1():
print('b1')
a1()
def b2():
print('b2')
if __name__ == '__main__':
b1()
Sie erhalten einen Importfehler: ImportError: cannot import name 'a1'
Aber wenn wir die Position von aus test.b ändern, importieren Sie b2 in A wie unten:
a.py
def a1():
print('a1')
b2()
from test.b import b2
Und wir können bekommen, was wir wollen:
b1
a1
b2
Ankit Patidar
Dies ist eine zirkuläre Abhängigkeit. Wir können dieses Problem lösen, indem wir verwenden importieren Modul oder Klasse oder Funktion, wo wir sie brauchten. Wenn wir diesen Ansatz verwenden, können wir die zirkuläre Abhängigkeit beheben
A.py
from B import b2
def a1():
print('a1')
b2()
B.py
def b1():
from A import a1
print('b1')
a1()
def b2():
print('b2')
if __name__ == '__main__':
b1()
Ich habe diesen Fehler auch gerade bekommen, aus einem anderen Grund …
from my_sub_module import my_function
Das Hauptskript hatte Windows-Zeilenenden. my_sub_module hatte UNIX-Zeilenenden. Wenn Sie sie so ändern, dass sie gleich sind, wurde das Problem behoben. Sie müssen auch die gleiche Zeichenkodierung haben.
11308100cookie-checkWas kann ich bei “ImportError: Name X kann nicht importiert werden” oder “AttributeError: … (höchstwahrscheinlich aufgrund eines zirkulären Imports)” tun?yes
In welcher Verzeichnisstruktur werden sie gespeichert und in welchen Verzeichnissen?
– Ben
12. Februar 2012 um 20:56 Uhr
Schauen Sie sich diese Antwort zum Schleifenimport in Python an: stackoverflow.com/questions/7199466/…
– Gregor
12. Februar 2012 um 20:56 Uhr
Im Allgemeinen ist es keine gute Programmierpraxis
from <module> import <name>
oderfrom <modlue> import *
. Importieren Sie besser unter dem Modulnamensraum, um zu verhindern, dass identisch benannte Referenzen überschrieben werden.– Joel Cornett
12. Februar 2012 um 20:57 Uhr
@jsells Sie sollten einfach Ihre Klassen anrufen
Entity
undVector
Anstatt vonEnt
undVect
, gibt es keinen Grund, solche Namen zu kürzen. Und ja, verwendenimport vector
und dannx = vector.Vector(0,0,0)
.– Benutzer2032433
18. April 2013 um 17:00 Uhr
Hey @Kevin, da du Java besser kennst, was ist dein Eindruck davon Artikel 2008 wobei sich der erste Satz des Autors darauf bezieht, wie zirkuläre Abhängigkeiten sind “ziemlich gängige Praxis” auf Java?
– HeyWatchThis
8. Mai 2014 um 20:52 Uhr