2015-11-13 16 views
6

Python ist eine sehr elegante Sprache. Nun, außer ... außer Importen. Ich kann es immer noch nicht so machen, wie es mir natürlich erscheint.Circular Imports Hell

Ich habe eine Klasse MyObjectA, die in Datei mypackage/myobjecta.py ist. Dieses Objekt verwendet einige Dienstprogrammfunktionen, die in mypackage/utils.py sind. Also in meiner ersten Zeile in myobjecta.py ich schreibe:

from mypackage.utils import util_func1, util_func2 

Aber einige der Utility-Funktionen erstellen und zurückgeben neue Instanzen von MyObjectA. Also muss ich in utils.py schreiben:

from mypackage.myobjecta import MyObjectA 

Nun, nein ich kann nicht. Dies ist ein zirkulärer Import und Python wird dies ablehnen.

Es gibt viele Fragen zu diesem Thema, aber keine scheint eine befriedigende Antwort zu geben. Von was ich in allen Antworten lesen kann:

  1. Reorganisieren Sie Ihre Module, Sie tun es falsch! Aber ich weiß nicht, wie besser, meine Module zu organisieren, auch in einem so einfachen Fall wie ich präsentiert.
  2. Versuchen nur import ... statt from ... import ... (persönlich hasse ich alle zu schreiben und möglicherweise Refactoring den vollen Namen Qualifier, ich liebe, genau zu sehen, was ich in Modul von der Außenwelt am Import). Würde das helfen? Ich bin mir nicht sicher, immer noch gibt es kreisförmige Importe.
  3. Hacks wie importieren etwas in den inneren Bereich eines Funktionskörpers nur eine Zeile, bevor Sie etwas aus anderen Modul verwenden.

Ich hoffe immer noch, es gibt die Lösung Nummer 4), die Pythonic im Sinne von funktional und elegant und einfach und funktionierend sein würde. Oder gibt es nicht?

Hinweis: Ich bin in erster Linie ein C++ - Programmierer, das obige Beispiel ist so einfach zu lösen, indem entsprechende Header eingefügt werden, die ich nicht glauben kann, dass es in Python nicht möglich ist.

+0

Von dem, was Sie sagen, würde ich entweder MyObjectA in utils.py setzen, weil einige Dienstprogrammfunktionen es zurückgibt, oder ich würde die Dienstprogrammfunktionen setzen, die ein MyObjectA in myobjecta.py zurückgibt. Aber das ist die Antwort 1) – DainDwarf

+0

Ich suchte nach Python zirkuläre Importe und fand mehrere Fragen. Hast du gesucht? –

+0

@ Dain: Ja, könnte sicherlich tun, wenn die Dienstprogrammfunktionen nur MyObjectA zurückgeben. Aber was, wenn sie auch MyObjectB oder MyObjectC usw. zurückgeben können? –

Antwort

0

Es gibt nichts hackish über etwas in einer Funktion Körper zu importieren, dann ist es ein absolut gültiges Muster:

def some_function(): 
    import logging 
    do_some_logging() 

Normalerweise ImportError s wegen der Art und Weise nur angehoben werden import() wertet Top-Level-Anweisungen der gesamten Datei, wenn sie aufgerufen .

Falls Sie haben keine Logik zirkuläre Abhängigkeit ... , nichts ist in Python unmöglich ...

Es gibt einen Weg, um es ist, wenn Sie positiv Ihre Importe auf wollen:

Von David Beazleys ausgezeichneter Rede Modules and Packages: Live and Let Die! - PyCon 2015, 1:54:00, hier ist ein Weg, um mit Kreis Einfuhren in Python zu tun:

try: 
    from images.serializers import SimplifiedImageSerializer 
except ImportError: 
    import sys 
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer'] 

Dies versucht SimplifiedImageSerializer zu importieren und wenn ImportError ausgelöst wird, weil es bereits importiert wird, wird es aus dem Importcache ziehen.

PS: Sie müssen diesen ganzen Beitrag in David Beazleys Stimme lesen.

+1

Danke, ich werde mir auf jeden Fall die Zeit nehmen, dieses Gespräch zu sehen. Nichtsdestotrotz ist das Importieren in die Funktion keine so gute Lösung, um es für die 'sehr python'-Medaille zu qualifizieren. Es verbirgt die Modulabhängigkeit und vergräbt sie in Code. Warum nicht alle Importe in Code dann? Ich vermisse die Logik darin ... Aber ja, es funktioniert die meiste Zeit. Und mit try/catch nur um das (IMHO) fehlerhafte Konzept der Importe in Python zu umgehen ist ... definitiv ein Hack. –

0

Importieren Sie nicht mypackage.utils zu Ihrem Hauptmodul, es existiert bereits in mypackage.myobjecta. Sobald Sie mypackage.myobjecta importieren, wird der Code von diesem Modul ausgeführt und Sie müssen nichts in Ihr aktuelles Modul importieren, da mypackage.myobjecta bereits fertig ist.

+0

Ist das eine gute Lösung? Was, wenn ich die Utility-Funktionen auch aus dem 'main'-Modul verwenden möchte. Dann würde ich diese Abhängigkeit verschleiern, indem ich "utils" nicht in "main" importiere. Auch aus der Sicht von 'myobjecta.py' ist die Verwendung von' utils.py' nur ein Implementierungsdetail. Es bringt potentielles Refactoring-Chaos mit sich, wenn ich später beschließe, dieses Implementierungsdetail zu ändern ... Und wie unterbricht dies den zirkulären Import zwischen 'myobjecta.py' und' utils.py'? Aber vielleicht habe ich den Punkt missverstanden. –

+0

können Sie sie wie folgt importieren: 'from mypackage.myobjecta import util_func1, util_func2', da sie bereits in diesem Paket sind – Nhor

+0

Aber wie ich bereits erwähnte, ist die Verwendung von' utils' aus 'myobjecta' nur ein Implementierungsdetail. Was, wenn ich das später ändere. Dann müsste ich alles umschreiben, was gleichzeitig "utils" und "myobjecta" verwendet. Ich persönlich halte dies für einen Hack, weil es den Benutzer dazu zwingt, die Implementierungsdetails zu kennen. Das ist kein gutes Design. Und übrigens. es bricht nicht den zirkulären Import zwischen "myobjecta" und "utils". Oder ist es? Ich verstehe es nicht. –

0

Die Art, wie ich es in meinem (ersten) Projekt geschafft habe, war das Kopieren und Einfügen des gesamten Moduls in den Körper des anderen und das Verwenden nur eines Imports. Code-Duplizierung, unelegant, aber es erlaubte mir weiterzugehen.

+0

Ich habe ähnliche Probleme. Ich bin kein Ptyhon-Export, aber das klingt schrecklich. Was hast du in deinem (zweiten) Projekt gemacht? – smerlung

+0

Es kam glücklicherweise nie wieder dazu, aber die Art, wie ich es jetzt tun würde, ist ein anderes Modul zu erstellen und die anderen beiden darin zu importieren. – postoronnim