Wie behandelt man eine zirkuläre Modulabhängigkeit in Python richtig?

8

Versuchen, ein gutes und richtiges Muster zu finden, um eine Abhängigkeit von einem Kreismodul in Python zu behandeln. Normalerweise besteht die Lösung darin, es zu entfernen (durch Refactoring); In diesem speziellen Fall möchten wir jedoch die Funktionalität haben, die den zirkulären Import erfordert.

BEARBEITEN : Laut den Antworten unten wäre der übliche Angriffswinkel für diese Art von Problem ein Refactor. Nehmen Sie jedoch für diese Frage an, dass dies keine Option ist (aus welchen Gründen auch immer).

Das Problem:

Das Modul logging benötigt das Modul configuration für einige seiner Konfigurationsdaten. Für einige der configuration -Funktionen würde ich jedoch gerne die benutzerdefinierten Protokollierungsfunktionen verwenden, die im Modul logging definiert sind. Offensichtlich verursacht das Importieren des Moduls logging in configuration einen Fehler.

Die möglichen Lösungen, die wir uns vorstellen können:

  1. Mach es nicht . Wie ich schon sagte, ist dies keine gute Option, es sei denn alle anderen Möglichkeiten sind hässlich und schlecht.

  2. Monkey-Patch das Modul . Das hört sich nicht schlecht an: Laden Sie das logging -Modul dynamisch in configuration nach dem ersten Import und bevor eine seiner Funktionen tatsächlich verwendet wird. Dies bedeutet jedoch, globale Variablen pro Modul zu definieren.

  3. Abhängigkeitsinjektion . Ich habe gelesen und bin in Abhängigkeitsinjektionsalternativen gelaufen (insbesondere im Java-Enterprise-Bereich) und sie beseitigen einige dieser Kopfschmerzen; Sie können jedoch zu kompliziert sein, um sie zu verwenden und zu verwalten, was wir vermeiden möchten. Mir ist jedoch nicht klar, wie das Panorama in Python aussieht.

Was ist eine gute Möglichkeit, diese Funktionalität zu aktivieren?

Vielen Dank!

    
Juan Carlos Coto 04.12.2013, 17:51
quelle

4 Antworten

4

Wie bereits gesagt, wird wahrscheinlich ein Refactoring benötigt. Laut den Namen könnte es in Ordnung sein, wenn ein Logging-Modul die Konfiguration verwendet, wenn man darüber nachdenkt, was in der Konfiguration sein soll, man denke über Konfigurationsparameter nach, dann stellt sich die Frage, warum überhaupt diese Konfiguration protokolliert wird.

Es besteht die Möglichkeit, dass die Teile des zu konfigurierenden Codes, die die Protokollierung verwenden, nicht zum Konfigurationsmodul gehören: es scheint so zu sein, als würde es irgendeine Art von Verarbeitung und Protokollierung von Ergebnissen oder Fehlern durchführen.

Ohne inneres Wissen und nur mit gesundem Menschenverstand sollte ein "Konfigurations" -Modul etwas Einfaches ohne viel Verarbeitung sein und es sollte ein Blatt in der Import-Struktur sein.

Ich hoffe, es hilft!

    
Sergio Ayestarán 04.12.2013, 23:05
quelle
3

Funktioniert das für Sie?

%Vor%

Jetzt kann ich einen Import machen b. Wenn der zirkuläre Import (verursacht durch die Anweisung import b in a) eine Ausnahme auslöst, wird diese abgefangen und verworfen. Natürlich muss Ihr gesamtes Modul b um einen zusätzlichen Blockabstand eingerückt sein, und Sie müssen wissen, wo die Variable HELLO in a deklariert ist.

Wenn Sie b.py nicht ändern wollen, indem Sie try: except: logic einfügen, können Sie die gesamte b-Quelle in eine neue Datei verschieben, sie c.py nennen und eine einfache Datei b.py erstellen das:

%Vor%

Dadurch wird der gesamte Namensraum von c nach b und Papier über den kreisförmigen Import importiert.

Ich merke, das ist ekelhaft, also erzähl niemandem davon.

    
Paul Cornelius 04.12.2013 21:57
quelle
2

Eine zyklische Modulabhängigkeit ist normalerweise ein Code-Geruch.

Es gibt an, dass ein Teil des Codes neu strukturiert werden sollte, damit er für beide Module extern ist.

    
Chris Dutrow 04.12.2013 20:01
quelle
2

Wenn ich also Ihr Anwendungsrecht richtig lese, greift logging auf configuration zu, um Konfigurationsdaten zu erhalten. % Co_de% hat jedoch einige Funktionen, die, wenn sie aufgerufen werden, erfordern, dass Zeug von configuration in logging importiert wird.

Wenn das der Fall ist (dh configuration benötigt nicht wirklich configuration , bis Sie Funktionen aufrufen), ist die Antwort einfach: Platziere in logging alle Importe von configuration bei Dateiende nach allen Klassen-, Funktions- und Konstantendefinitionen.

Python liest Dinge von oben nach unten: Wenn es auf eine logging -Anweisung in import trifft, führt es es aus, aber zu diesem Zeitpunkt existiert configuration bereits als ein Modul, das importiert werden kann, selbst wenn es das ist noch nicht vollständig initialisiert: Es hat nur die Attribute, die deklariert wurden, bevor die Anweisung configuration ausgeführt wurde.

Ich stimme aber den anderen zu, dass zirkuläre Importe normalerweise ein Code-Geruch sind.

    
Max Noel 05.12.2013 01:24
quelle