In PEP 08 heißt es:
Importe werden immer am Anfang der Datei platziert, direkt nach Modulkommentaren und Dokumentzeichenfolgen sowie vor Modulglobalen und -konstanten.
Wenn jedoch die Klasse / Methode / Funktion, die ich importiere, nur in seltenen Fällen verwendet wird, ist es sicherlich effizienter, den Import bei Bedarf durchzuführen?
Ist das nicht:
class SomeClass(object):
def not_often_called(self)
from datetime import datetime
self.datetime = datetime.now()
effizienter als das?
from datetime import datetime
class SomeClass(object):
def not_often_called(self)
self.datetime = datetime.now()
quelle
Das Einfügen der import-Anweisung in eine Funktion kann zirkuläre Abhängigkeiten verhindern. Wenn Sie beispielsweise zwei Module haben, X.py und Y.py, und beide sich gegenseitig importieren müssen, führt dies zu einer zirkulären Abhängigkeit, wenn Sie eines der Module importieren, was eine Endlosschleife verursacht. Wenn Sie die import-Anweisung in eines der Module verschieben, wird nicht versucht, das andere Modul zu importieren, bis die Funktion aufgerufen wird, und dieses Modul wird bereits importiert, also keine Endlosschleife. Lesen Sie hier mehr - effbot.org/zone/import-confusion.htm
quelle
Ich habe die Praxis übernommen, alle Importe in die Funktionen zu setzen, die sie verwenden, und nicht oben im Modul.
Der Vorteil, den ich bekomme, ist die Fähigkeit, zuverlässiger umzugestalten. Wenn ich eine Funktion von einem Modul in ein anderes verschiebe, weiß ich, dass die Funktion weiterhin funktioniert, wenn das gesamte Erbe des Testens intakt bleibt. Wenn ich meine Importe oben im Modul habe und eine Funktion verschiebe, verbringe ich viel Zeit damit, die Importe des neuen Moduls vollständig und minimal zu machen. Eine Refactoring-IDE kann dies irrelevant machen.
Es gibt eine Geschwindigkeitsstrafe, wie an anderer Stelle erwähnt. Ich habe dies in meiner Bewerbung gemessen und festgestellt, dass es für meine Zwecke unbedeutend ist.
Es ist auch schön, alle Modulabhängigkeiten im Voraus sehen zu können, ohne auf die Suche zurückgreifen zu müssen (z. B. grep). Der Grund, warum ich mich für Modulabhängigkeiten interessiere, ist im Allgemeinen, dass ich ein gesamtes System mit mehreren Dateien installiere, umgestalte oder verschiebe, nicht nur ein einzelnes Modul. In diesem Fall werde ich trotzdem eine globale Suche durchführen, um sicherzustellen, dass ich die Abhängigkeiten auf Systemebene habe. Daher habe ich keine globalen Importe gefunden, um mein Verständnis eines Systems in der Praxis zu verbessern.
Normalerweise setze ich den Import von
sys
in dieif __name__=='__main__'
Prüfung und übergebe dann Argumente (wiesys.argv[1:]
) an einemain()
Funktion. Dies ermöglicht mir die Verwendungmain
in einem Kontext, insys
den nicht importiert wurde.quelle
def main(): print(sys.argv); if True: import sys; main();
Sie müsstenif __name__=='__main__'
eine Funktion einschließen , um einen neuen Namespace zu erstellen.Meistens wäre dies aus Gründen der Klarheit nützlich und sinnvoll, aber dies ist nicht immer der Fall. Im Folgenden finden Sie einige Beispiele für Umstände, unter denen Modulimporte möglicherweise an anderer Stelle ausgeführt werden.
Erstens könnten Sie ein Modul mit einem Komponententest des Formulars haben:
Zweitens müssen Sie möglicherweise zur Laufzeit ein anderes Modul bedingt importieren.
Es gibt wahrscheinlich andere Situationen, in denen Sie möglicherweise Importe in andere Teile des Codes einfügen.
quelle
Die erste Variante ist in der Tat effizienter als die zweite, wenn die Funktion entweder null oder einmal aufgerufen wird. Mit dem zweiten und den folgenden Aufrufen ist der Ansatz "Jeden Anruf importieren" jedoch weniger effizient. Siehe diesen Link eine Technik zum verzögerten Laden, bei der das Beste aus beiden Ansätzen durch einen "verzögerten Import" kombiniert wird.
Es gibt jedoch andere Gründe als die Effizienz, warum Sie einen dem anderen vorziehen könnten. Ein Ansatz besteht darin, jemandem, der den Code liest, viel klarer zu machen, welche Abhängigkeiten dieses Modul aufweist. Sie haben auch sehr unterschiedliche Fehlereigenschaften - das erste schlägt beim Laden fehl, wenn kein "datetime" -Modul vorhanden ist, während das zweite erst nach dem Aufruf der Methode ausfällt.
Hinweis hinzugefügt: In IronPython können Importe erheblich teurer sein als in CPython, da der Code beim Importieren im Grunde genommen kompiliert wird.
quelle
Curt macht einen guten Punkt: Die zweite Version ist klarer und wird eher beim Laden als später und unerwartet ausfallen.
Normalerweise mache ich mir keine Sorgen um die Effizienz des Ladens von Modulen, da es (a) ziemlich schnell ist und (b) meistens nur beim Start geschieht.
Wenn Sie Schwergewichts - Module zu unerwarteten Zeiten laden haben, macht es wahrscheinlich mehr Sinn , sie mit der dynamischen zu Laden -
__import__
Funktion und seine sicher zu fangenImportError
Ausnahmen, und sie in angemessener Weise zu behandeln.quelle
Ich würde mir keine Sorgen über die Effizienz machen, das Modul im Voraus zu stark zu laden. Der vom Modul belegte Speicher wird nicht sehr groß sein (vorausgesetzt, er ist modular genug) und die Startkosten sind vernachlässigbar.
In den meisten Fällen möchten Sie die Module oben in die Quelldatei laden. Für jemanden, der Ihren Code liest, ist es viel einfacher zu erkennen, welche Funktion oder welches Objekt von welchem Modul stammt.
Ein guter Grund, ein Modul an eine andere Stelle im Code zu importieren, ist die Verwendung in einer Debugging-Anweisung.
Zum Beispiel:
Ich könnte dies debuggen mit:
Der andere Grund, Module an anderer Stelle im Code zu importieren, besteht natürlich darin, dass Sie sie dynamisch importieren müssen. Das liegt daran, dass Sie so ziemlich keine Wahl haben.
Ich würde mir keine Sorgen über die Effizienz machen, das Modul im Voraus zu stark zu laden. Der vom Modul belegte Speicher wird nicht sehr groß sein (vorausgesetzt, er ist modular genug) und die Startkosten sind vernachlässigbar.
quelle
Es ist ein Kompromiss, den nur der Programmierer treffen kann.
Fall 1 spart Speicherplatz und Startzeit, indem das datetime-Modul nicht importiert wird (und die erforderliche Initialisierung durchgeführt wird), bis es benötigt wird. Beachten Sie, dass der Import "nur beim Aufruf" auch "jedes Mal beim Aufruf" bedeutet, sodass jeder Aufruf nach dem ersten immer noch den zusätzlichen Aufwand für den Import verursacht.
Fall 2 spart einige Ausführungszeit und Latenz, indem Sie datetime vorher importieren, damit not_often_called () schneller zurückkehrt, wenn dies der Fall ist genannt, und auch nicht bei jedem Aufruf den Aufwand einer Einfuhr entstehen.
Neben der Effizienz ist es einfacher, Modulabhängigkeiten im Voraus zu erkennen, wenn die Importanweisungen im Vordergrund stehen. Wenn Sie sie im Code ausblenden, kann es schwieriger werden, leicht zu finden, von welchen Modulen etwas abhängt.
Persönlich folge ich im Allgemeinen dem PEP, mit Ausnahme von Unit-Tests und solchen, die ich nicht immer laden möchte, weil ich weiß , dass sie nur für Testcode verwendet werden.
quelle
sys.modules
Nachschlagen des Moduls können leicht durch die Einsparungen ausgeglichen werden, da nur ein lokaler Name anstelle eines globalen Namens gesucht werden muss .Hier ist ein Beispiel, in dem alle Importe ganz oben stehen (dies ist das einzige Mal, dass ich dies tun muss). Ich möchte einen Unterprozess sowohl unter Un * x als auch unter Windows beenden können.
(Zur Überprüfung: Was John Millikin gesagt hat.)
quelle
Dies ist wie bei vielen anderen Optimierungen - Sie opfern eine gewisse Lesbarkeit für die Geschwindigkeit. Wie John bereits erwähnt hat, sollten Sie Ihre Profiling-Hausaufgaben erledigen und feststellen, dass dies eine ausreichend nützliche Änderung ist und Sie die zusätzliche Geschwindigkeit benötigen. Es wäre wahrscheinlich gut, eine Notiz über alle anderen Importe zu machen:
quelle
Die Modulinitialisierung erfolgt nur einmal - beim ersten Import. Wenn das betreffende Modul aus der Standardbibliothek stammt, werden Sie es wahrscheinlich auch aus anderen Modulen in Ihrem Programm importieren. Für ein Modul, das so häufig wie datetime ist, ist es wahrscheinlich auch eine Abhängigkeit für eine Reihe anderer Standardbibliotheken. Die Importanweisung würde dann sehr wenig kosten, da die Modulinitialisierung bereits stattgefunden hätte. Zu diesem Zeitpunkt wird lediglich das vorhandene Modulobjekt an den lokalen Bereich gebunden.
Kombinieren Sie diese Informationen mit dem Argument für die Lesbarkeit, und ich würde sagen, dass es am besten ist, die import-Anweisung im Modulbereich zu haben.
quelle
Nur um Moes Antwort zu vervollständigen und die ursprüngliche Frage :
Wenn wir uns mit zirkulären Abhängigkeiten befassen müssen, können wir einige "Tricks" machen. Angenommen, wir arbeiten mit Modulen
a.py
undb.py
diese enthaltenx()
bzw. by()
. Dann:from imports
am unteren Rand des Moduls verschieben.from imports
der Funktionen oder Methoden verschieben, für die der Import tatsächlich erforderlich ist (dies ist nicht immer möglich, da Sie sie möglicherweise von mehreren Stellen aus verwenden).from imports
, um einen Import zu erhalten, der wie folgt aussieht:import a
Also zum Schluss. Wenn Sie sich nicht mit zirkulären Abhängigkeiten befassen und einen Trick ausführen, um sie zu vermeiden, ist es aus den Gründen, die bereits in anderen Antworten auf diese Frage erläutert wurden, besser, alle Importe an die Spitze zu setzen. Und bitte, wenn diese "Tricks" einen Kommentar enthalten, ist es immer willkommen! :) :)
quelle
Neben den bereits gegebenen hervorragenden Antworten ist anzumerken, dass die Platzierung von Importen nicht nur eine Frage des Stils ist. Manchmal weist ein Modul implizite Abhängigkeiten auf, die zuerst importiert oder initialisiert werden müssen, und ein Import auf oberster Ebene kann zu Verstößen gegen die erforderliche Ausführungsreihenfolge führen.
Dieses Problem tritt häufig in der Python-API von Apache Spark auf, wo Sie den SparkContext initialisieren müssen, bevor Sie Pyspark-Pakete oder -Module importieren. Es ist am besten, Pyspark-Importe in einem Bereich zu platzieren, in dem der SparkContext garantiert verfügbar ist.
quelle
Ich war überrascht, dass die tatsächlichen Kostenzahlen für die wiederholten Ladeprüfungen nicht bereits veröffentlicht wurden, obwohl es viele gute Erklärungen dafür gibt, was zu erwarten ist.
Wenn Sie oben importieren, nehmen Sie den Lasttreffer, egal was passiert. Das ist ziemlich klein, aber normalerweise in Millisekunden, nicht in Nanosekunden.
Wenn Sie innerhalb einer Funktion (en) zu importieren, dann nehmen Sie nur den Treffer zum Laden , wenn und wenn eine dieser Funktionen wird zuerst genannt. Wie viele darauf hingewiesen haben, sparen Sie die Ladezeit, wenn dies überhaupt nicht geschieht. Aber wenn die Funktion (en) viel aufgerufen, nehmen Sie ein , obwohl viel kleiner Hit wiederholt (für die Überprüfung , dass es wurde geladen worden ist , nicht für tatsächlich Nachladen). Andererseits sparen Sie, wie @aaronasterling hervorhob, auch ein wenig, da beim Importieren innerhalb einer Funktion die Funktion etwas schnellere lokale Variablensuchen verwendet , um den Namen später zu identifizieren ( http://stackoverflow.com/questions/477096/python-). Import-Coding-Stil / 4789963 # 4789963 ).
Hier sind die Ergebnisse eines einfachen Tests, bei dem einige Dinge aus einer Funktion importiert werden. Die angegebenen Zeiten (in Python 2.7.14 auf einem Intel Core i7 mit 2,3 GHz) sind unten aufgeführt (der zweite Anruf, der mehr als spätere Anrufe entgegennimmt, scheint konsistent zu sein, obwohl ich nicht weiß, warum).
Der Code:
quelle
Ich strebe keine vollständige Antwort an, da andere dies bereits sehr gut gemacht haben. Ich möchte nur einen Anwendungsfall erwähnen, wenn ich das Importieren von Modulen in Funktionen besonders nützlich finde. Meine Anwendung verwendet Python-Pakete und -Module, die an einem bestimmten Ort als Plugins gespeichert sind. Während des Anwendungsstarts durchläuft die Anwendung alle Module am Speicherort und importiert sie. Anschließend werden die Module überprüft und es werden einige Einhängepunkte für die Plugins gefunden (in meinem Fall handelt es sich um eine Unterklasse einer bestimmten Basisklasse mit einer eindeutigen ID) registriert sie. Die Anzahl der Plugins ist groß (jetzt Dutzende, aber vielleicht Hunderte in der Zukunft) und jedes von ihnen wird ziemlich selten verwendet. Der Import von Bibliotheken von Drittanbietern oben auf meinen Plugin-Modulen war beim Start der Anwendung eine kleine Strafe. Insbesondere einige Bibliotheken von Drittanbietern sind schwer zu importieren (z. B. der Import von Plotly versucht sogar, eine Verbindung zum Internet herzustellen und etwas herunterzuladen, das dem Start etwa eine Sekunde hinzufügte). Durch die Optimierung der Importe (die nur in den Funktionen aufgerufen werden, in denen sie verwendet werden) in den Plugins konnte ich den Start von 10 Sekunden auf etwa 2 Sekunden verkürzen. Das ist ein großer Unterschied für meine Benutzer.
Meine Antwort lautet also nein, setzen Sie die Importe nicht immer ganz oben auf Ihre Module.
quelle
Es ist interessant, dass bisher keine einzige Antwort die Parallelverarbeitung erwähnte, bei der möglicherweise ERFORDERLICH ist, dass die Importe in der Funktion enthalten sind, wenn der serialisierte Funktionscode auf andere Kerne übertragen wird, z. B. wie bei ipyparallel.
quelle
Durch den Import von Variablen / lokalem Gültigkeitsbereich innerhalb einer Funktion kann ein Leistungsgewinn erzielt werden. Dies hängt von der Verwendung des importierten Objekts innerhalb der Funktion ab. Wenn Sie viele Male eine Schleife ausführen und auf ein globales Modulobjekt zugreifen, kann es hilfreich sein, es als lokal zu importieren.
test.py
runlocal.py
run.py
Eine Zeit unter Linux zeigt einen kleinen Gewinn
echt ist wanduhr. Benutzer ist Zeit im Programm. sys ist Zeit für Systemaufrufe.
https://docs.python.org/3.5/reference/executionmodel.html#resolution-of-names
quelle
Lesbarkeit
Zusätzlich zur Startleistung muss ein Lesbarkeitsargument für die Lokalisierung von
import
Anweisungen angegeben werden. Nehmen Sie zum Beispiel die Python-Zeilennummern 1283 bis 1296 in meinem aktuellen ersten Python-Projekt:Wenn die
import
Aussage oben in der Datei wäre, müsste ich weit nach oben scrollen oder drücken Home, um herauszufinden, was istET
. Dann müsste ich zurück zu Zeile 1283 navigieren, um den Code weiterzulesen.Selbst wenn sich die
import
Anweisung an der Spitze der Funktion (oder Klasse) befindet, wie viele sie platzieren würden, wäre ein Auf- und Abblättern erforderlich.Das Anzeigen der Gnome-Versionsnummer wird selten durchgeführt, sodass
import
oben in der Datei unnötige Startverzögerungen auftreten.quelle
Ich möchte einen meiner Fälle erwähnen, der den von @John Millikin und @VK erwähnten sehr ähnlich ist:
Optionale Importe
Ich mache Datenanalysen mit Jupyter Notebook und verwende dasselbe IPython-Notebook als Vorlage für alle Analysen. In einigen Fällen muss ich Tensorflow importieren, um einige schnelle Modellläufe durchzuführen, aber manchmal arbeite ich an Orten, an denen Tensorflow nicht eingerichtet ist / nur langsam importiert wird. In diesen Fällen kapsle ich meine Tensorflow-abhängigen Operationen in eine Hilfsfunktion, importiere Tensorflow in diese Funktion und binde sie an eine Schaltfläche.
Auf diese Weise konnte ich "Neustart-and-Run-All" durchführen, ohne auf den Import warten zu müssen oder den Rest der Zellen wieder aufnehmen zu müssen, wenn dies fehlschlägt.
quelle
Dies ist eine faszinierende Diskussion. Wie viele andere hatte ich dieses Thema noch nie in Betracht gezogen. Ich musste die Importe in den Funktionen haben, weil ich das Django ORM in einer meiner Bibliotheken verwenden wollte. Ich musste
django.setup()
vor dem Importieren meiner Modellklassen aufrufen und da dies oben in der Datei war, wurde es aufgrund der IoC-Injektorkonstruktion in einen vollständig nicht-Django-Bibliothekscode gezogen.Ich habe ein bisschen herumgehackt und am Ende
django.setup()
den Singleton-Konstruktor und den entsprechenden Import an die Spitze jeder Klassenmethode gesetzt. Jetzt funktionierte das gut, machte mich aber unruhig, weil die Importe nicht an der Spitze standen und ich mir auch Sorgen über die zusätzliche Zeit der Importe machte. Dann bin ich hierher gekommen und habe mit großem Interesse gelesen, dass alle dies annehmen.Ich habe einen langen C ++ - Hintergrund und verwende jetzt Python / Cython. Ich gehe davon aus, dass Sie die Importe nicht in die Funktion einfügen, es sei denn, dies führt zu einem profilierten Engpass. Es ist nur so, als würden Sie Platz für Variablen deklarieren, bevor Sie sie benötigen. Das Problem ist, dass ich Tausende von Codezeilen mit allen Importen oben habe! Also denke ich, ich werde es von jetzt an tun und die ungerade Datei hier und da ändern, wenn ich durch bin und die Zeit habe.
quelle