Immer öfters schlage ich mich mit import loops herum.
Bei PyLucid ist die models.py einfach zu groß geworden. Also hab ich es in ein Package verwandelt.
Es gibt allerdings diverse Abhängigkeiten zwischen den Modellen. Zwar kann man z.B. beim models.ForeignKey() einen String übergeben, statt direkt dem Objekt. Aber an manchen Stellen brauche ich anderen Model Klassen.
Als Lösung kann man den import von Modulebene in die Klasse verschieben, aber das ist unschön ist.
Welche Strategien nutzt ihr dafür?
import loops...
Die einzig wirklich sinnvolle Strategie ist eigentlich, solche Abhängigkeiten gar nicht erst entstehen zu lassen. Wenn Du viele zirkuläre Abhängigkeiten hast, ist das Design wohl verbesserungsbedürftig. Eine große Anzahl zirkulärer Abhängigkeiten ist eigentlich ein Zeichen dafür, dass die Klassen, die Du auf verschiedene Module verteilt hast, wohl eher in ein einziges Modul gehören, oder zumindest in ein Paket, dass dann auf Paketebene die einzelnen Module verbindet.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Naja, Modelle die mit FK oder M2M verbunden sind haben halt was miteinander zu tun...
Das Problem ist auch: Ich finde es schwer das ganze zu debuggen. Denn man bekommt nur den Fehler "ImportError: cannot import name FooBar". Was interessant wäre, warum python das Modul nicht importieren kann
Das Problem ist auch: Ich finde es schwer das ganze zu debuggen. Denn man bekommt nur den Fehler "ImportError: cannot import name FooBar". Was interessant wäre, warum python das Modul nicht importieren kann

Du solltest dir klarmachen, wie der Importmechanismus von Python funktioniert. Python kann die Module sehr wohl importieren, faktisch sind sie ja sogar schon importiert (und der Code darin wird gerade ausgeführt), nur die Namen im Modul existieren eben noch nicht.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Was soll Python auch groß anders sagen? "Hilfe, du hast einen zirkulären Import!"? Aus Sicht von Python kann eben der Name nicht gefunden werden und nichts anderes. Und woran es liegt, wird, wenn man Python kennt, auch recht schnell klar, denn das schöne an Python ist ja, dass man für Ausnahmen Tracebacks für umsonst bekommt und nicht erst einen Debugger oder sonst etwas anwerfen muss.
Nehmen wir also an, ich habe ein Modul `main`, das `a` importiert. `a` hat irgendwas an den Namen `A` gebunden. Zuvor importiert `a` jedoch das Modul `b` und `b` importiert wiederum aus `A` aus `a`. Also:
Wenn man das jetzt ausführt, wird eine Ausnahme geworfen und man erhält einen Traceback.
Also schaut man sich an, was passiert. Wenn man in `main` anfängt, sieht man, dass `a` importiert wird. Also macht man sich klar, was das bedeutet. Das Modul wird gesucht, geparst usw., dann wird ein Modulobjekt in `sys.modules` gesteckt und dann wird einfach der Code im Modul ausgeführt, der dann von oben nach unten abläuft. Danach sieht man, dass eben der Code in `a` wiederum `b` importiert. Der Ablauf ist analog zu `a`. Und dann sieht man, dass in `b` eben wieder `a` importiert wird. Was passiert jetzt aber hier? Module werden in Python gecachet, weshalb `a` nicht noch einmal neu geladen wird, sondern es wird das Modulobjekt aus `sys.modules` verwendet. Da der Code im Modul jedoch von oben nach unten ausgeführt wird, `A` in `a` also erst nach der Importanweisung erstellt wird, kann `A` eben nicht importiert werden. Würde man jetzt beispielsweise das Modul `a` so ändern:
würde keine Ausnahme geworfen werden.
Von daher ist ein zirkulärer Import IMHO also nicht unbedingt schwer zu debuggen (immerhin ist er völlig offensichtlich im Traceback zu erkennen), sondern kann eher auf Grund fehlender Kenntnisse über den Importmechanismus nicht erklärt werden.
Nehmen wir also an, ich habe ein Modul `main`, das `a` importiert. `a` hat irgendwas an den Namen `A` gebunden. Zuvor importiert `a` jedoch das Modul `b` und `b` importiert wiederum aus `A` aus `a`. Also:
Code: Alles auswählen
# main
import a
#a
import b
A = 42
# b
from a import A
Code: Alles auswählen
Traceback (most recent call last):
File "main.py", line 1, in <module>
import a
File "a.py", line 1, in <module>
import b
File "b.py", line 1, in <module>
from a import A
ImportError: cannot import name A
Code: Alles auswählen
# a
A = 42
import b
Von daher ist ein zirkulärer Import IMHO also nicht unbedingt schwer zu debuggen (immerhin ist er völlig offensichtlich im Traceback zu erkennen), sondern kann eher auf Grund fehlender Kenntnisse über den Importmechanismus nicht erklärt werden.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)