Importieren von Python-Modulen zum Zeitpunkt der Verwendung

8

Oft mache ich in meinen persönlichen Python-Bibliotheken so etwas:

class MyClass:

    # ...

    def plot(self):
        import someGraphicsLibrary as graphicslib
        graphicslib.plot(self.data)

Der Grund dafür ist, dass die Initialisierung someGraphicsLibraryeinige Zeit in Anspruch nimmt, bis zu einigen Sekunden für eine der von mir verwendeten Bibliotheken. Ich muss meine Ergebnisse nicht immer zeichnen, wenn ich diese Klasse verwende. Daher ist es sinnvoll, sie erst dann zu importieren, wenn sie tatsächlich verwendet wird, wenn überhaupt.

Dies scheint gut zu funktionieren, aber ich glaube nicht, dass ich es im Code eines anderen gesehen habe. Meine Frage ist also einfach, ob dies als gute Praxis angesehen wird. Gibt es versteckte Fallstricke, die zu erwarten sind, wenn man die Dinge so macht?

Nathaniel
quelle
1
Dies ist einfach eine Form des faulen Ladens , was nicht besonders ist.
Doc Brown
1
Abgesehen davon, dass Sie vielleicht ein bisschen hässlich sind, gibt es keinen wirklichen Grund, warum Sie dies nicht tun könnten. Und wenn der Bibliotheksimport so lange dauert, gibt es sogar einen legitimen Grund dafür. Ich würde nur darauf hinweisen, dies selten zu tun. Die meisten Importe sollten nicht so langsam sein.
Neil
@DocBrown Ich sage nicht, dass es etwas Besonderes ist, sondern frage nur, ob es speziell in Python als gute / schlechte Praxis angesehen wird.
Nathaniel
@ Nathaniel: Es scheint einen abergläubischen Glauben an die Existenz absoluter "Best Practices" unter vielen Entwicklern zu geben - was meiner Meinung nach Unsinn ist, jede "Praxis" hat Vor- und Nachteile, und was gut oder schlecht ist, kann nur im Einzelnen bewertet werden Kontext. Ihr Beispiel oben erscheint mir vernünftig, es ist einfach und klar, und der einzige wirkliche Nachteil ist, dass es schwieriger wird, alle Abhängigkeiten eines Moduls auf einen Blick zu erkennen (was Punkt 3 in Kevins Antwort ist). Wenn Sie also der Meinung sind, dass die Leistungsverbesserung den Aufwand wert ist, ist diese Übung gut, wenn nicht, ist diese Übung schlecht.
Doc Brown

Antworten:

9

Dies ist aus mehreren Gründen normalerweise keine gute Praxis:

  1. Meistens ist die Methode schnell, aber wenn Sie sie zum ersten Mal aufrufen, ist sie langsam. Das ist viel weniger vorhersehbar als ein Import zur Startzeit.
  2. Wenn der Import aus einer Reihe von Gründen fehlschlägt, werden Sie ihn erst kennen, wenn Sie die Methode zur Laufzeit aufrufen.
  3. Es ist schwieriger zu erkennen, von welchen Modulen Ihr Modul abhängt, da sie nicht oben in der Datei aufgeführt sind.
  4. Wenn der Import eines Moduls buchstäblich "einige Sekunden" dauert, kann es in seiner Importzeitlogik zu viel bewirken. Die Importzeitlogik sollte im Allgemeinen "gerade genug" tun, um das Modul nutzbar zu machen, und sollte nicht darum herumgehen, schwere globale Objekte zu erstellen. Gelegentlich sind solche Objekte notwendig, sollten aber sorgfältig geprüft werden.

Manchmal ist dies jedoch eine gute Idee, zum Beispiel:

  1. Wenn Sie ein Array-ähnliches implementieren , müssen Sie es möglicherweise numpyin Ihrer __array__()Methode verwenden. Möglicherweise möchten Sie sich jedoch nicht auf numpydie anderen Funktionen Ihres Moduls verlassen. Es ist daher besser, nur numpyinnerhalb von __array__()zu importieren , um die zusätzliche Abhängigkeit zu vermeiden, wenn sie nicht benötigt wird. Dies leidet nicht unter den Problemen 1 und 2, da numpyes bereits einmal importiert wurde (es ist das, was __array__()an erster Stelle aufgerufen wird!), Und es leidet nicht unter Problem 3, da numpyes sich nicht um eine "echte" Abhängigkeit Ihres Moduls handelt.
  2. Vor PEP 553 sah ein Haltepunkt traditionell so aus : import pdb; pdb.set_trace(). Sie möchten nicht import pdban die Spitze des Moduls setzen, da der Haltepunkt eine temporäre Codezeile ist, die gelöscht wird. Wenn Sie den Import weit weg verschieben, wird dies unnötig schwierig. Dies war veraltet, als das eingebaute System breakpoint()hinzugefügt wurde, sodass Sie jetzt keinen Inline-Import benötigen.
Kevin
quelle
4
Sie haben vergessen zu erwähnen, dass das vom OP veröffentlichte Beispiel wie eines aussieht, das zum Fall "Gute Idee Nr. 1" in Ihrer Antwort passt. Es sieht aus wie eine Klasse oder ein Modul mit einer Kernfunktionalität, die unabhängig vom Plotten ist und möglicherweise ohne die Grafikbibliothek verwendet wird.
Doc Brown
@DocBrown: MyClassist kein aussagekräftiges Substantiv, also denke ich, dass Sie zu Schlussfolgerungen springen.
Kevin
Nun, ich habe mir die Zeit genommen, den Beitrag vollständig zu lesen. Vielleicht habe ich ein bisschen geraten, aber mal sehen, was das OP darüber denkt (und versteh mich nicht falsch, deine Antwort hat bereits eine positive Bewertung von mir erhalten).
Doc Brown
@ Kevin Doc Browns erster Kommentar ist eine korrekte Interpretation meines Beitrags. (+1, das ist eine hilfreiche Antwort.)
Nathaniel