744 Stimmen

Was kann ich gegen "ImportError: Kann den Namen X nicht importieren" oder "AttributeError: ... (wahrscheinlich aufgrund eines zirkulären Imports)" tun?

Ich habe einige Codefragmente, die sich über mehrere Dateien erstrecken und versuchen, sich gegenseitig zu importieren, wie folgt:

main.py:

from entity import Ent

entity.py:

from physics import Physics
class Ent:
    ...

physics.py:

from entity import Ent
class Physics:
    ...

Dann führe ich main.py aus und erhalte den folgenden Fehler:

Traceback (most recent call last):
File "main.py", line 2, in 
    from entity import Ent
File ".../entity.py", line 5, in 
    from physics import Physics
File ".../physics.py", line 2, in 
    from entity import Ent
ImportError: cannot import name Ent

Ich gehe davon aus, dass der Fehler darauf zurückzuführen ist, dass ich entity zweimal importiere - einmal in main.py und später in physics.py - aber wie kann ich das Problem umgehen?


Siehe auch <a href="https://stackoverflow.com/questions/744373">Was passiert bei der Verwendung von gegenseitigen oder zirkulären Imports in Python?</a> für einen allgemeinen Überblick darüber, was erlaubt ist und was ein Problem bezüglich zirkulärer Imports verursacht. Siehe <a href="https://stackoverflow.com/questions/22187279">Warum scheinen zirkuläre Imports weiter oben im Aufrufstapel zu funktionieren, lösen aber dann einen ImportError weiter unten aus?</a> für technische Details darüber, <strong>warum und wie</strong> das Problem auftritt.

1 Stimmen

@jsells Du solltest deine Klassen einfach Entity und Vektor nennen, anstatt Ent und Vect, es gibt keinen Grund, solche Namen zu kürzen. Und ja, benutze import vektor und dann x = vektor.Vektor(0,0,0).

8 Stimmen

Hey @Kevin, da du Java besser kennst, was ist dein Eindruck von diesem Artikel von 2008, in dem der Autor im ersten Satz darauf hinweist, dass zirkuläre Abhängigkeiten in Java "ziemlich weit verbreitet" sind?

1 Stimmen

Jede wichtige Sprache unterstützt zirkuläre Imports ohne Probleme... C#, C, C++, Java, Objective-C... Wir haben nicht das Jahr 1991.

22voto

Ankit Patidar Punkte 449

Dies ist eine zirkuläre Abhängigkeit. Wir können dieses Problem lösen, indem wir das import Modul oder die Klasse oder Funktion dort verwenden, wo es benötigt wird. 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()

21voto

marengaz Punkte 1509

Ich habe diesen Fehler auch bekommen, aber aus einem anderen Grund...

from my_sub_module import my_function

Das Hauptskript hatte Windows-Zeilenumbrüche. my_sub_module hatte UNIX-Zeilenumbrüche. Indem ich sie angepasst habe, um sie gleich zu machen, wurde das Problem behoben. Sie müssen auch die gleiche Zeichenkodierung haben.

17voto

DuniC Punkte 223

Das Problem ist klar: zyklische Abhängigkeit zwischen Namen in den Modulen entity und physics.

Unabhängig davon, ob das gesamte Modul oder nur eine Klasse importiert wird, müssen die Namen geladen werden.

Schau dir dieses Beispiel an:

# a.py
import b
def foo():
  pass
b.bar()

# b.py
import a
def bar():
  pass
a.foo()

Dies wird kompiliert zu:

# a.py
# import b
# b.py
# import a # ignoriert, bereits importiert
def bar():
  pass
a.foo()
# Name a.foo ist nicht definiert!!!
# Import von b abgeschlossen!
def foo():
  pass
b.bar()
# fertig!

Mit einer kleinen Änderung können wir dies lösen:

# a.py
def foo():
  pass
import b
b.bar()

# b.py
def bar():
  pass
import a
a.foo()

Dies wird kompiliert zu:

# a.py
def foo():
  pass
# import b
# b.py
def bar():
  pass
# import a # ignoriert, bereits importiert
a.foo()
# Import von b abgeschlossen!
b.bar()
# fertig!

16voto

Tomasz Bartkowiak Punkte 8157

Wie bereits erwähnt, wird dies durch eine zyklische Abhängigkeit verursacht. Was nicht erwähnt wurde, ist, dass wenn Sie das Python Typing-Modul verwenden und eine Klasse importieren, die nur zur Annotation von Typen verwendet wird, können Sie Forward-Verweise verwenden:

Wenn ein Typ-Hinweis Namen enthält, die noch nicht definiert wurden, kann diese Definition als Zeichenfolgeliteral ausgedrückt werden, um später aufgelöst zu werden.

und entfernen Sie die Abhängigkeit (den Import), z.B. anstelle von

from my_module import Tree

def func(arg: Tree):
    # code

tun Sie:

def func(arg: 'Tree'):
    # code

(beachten Sie die entfernte import-Anweisung)

12voto

Paul Punkte 3263

Versuchen Sie diese Lösung: Benennen Sie Ihr funktionierendes Python-Skript um

Sie sollten nicht Ihr aktuelles Python-Skript mit dem Namen eines anderen Moduls benennen, das Sie importieren, da Sie diesen Fehler erhalten werden.

Beispiel:

  1. Sie arbeiten in medicaltorch.py
  2. in diesem Skript haben Sie: from medicaltorch import X where medicaltorch ein separates installiertes Modul sein soll

Dies schlägt fehl mit dem ImportError, da 2 Dinge auf medicaltorch verweisen

Also benennen Sie einfach Ihr funktionierendes Python-Skript in 1 um.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X