Ich habe einen lange laufenden Python-Server und möchte einen Dienst aktualisieren können, ohne den Server neu zu starten. Wie geht das am besten?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
Markus Harrison
Ich habe einen lange laufenden Python-Server und möchte einen Dienst aktualisieren können, ohne den Server neu zu starten. Wie geht das am besten?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
Sie können ein Modul erneut laden, wenn es bereits importiert wurde, indem Sie verwenden importlib.reload()
:
from importlib import reload # Python 3.4+
import foo
while True:
# Do some things.
if is_changed(foo):
foo = reload(foo)
In Python2, reload
war eingebaut. In Python 3 war es das gerührt zum imp
Modul. In 3.4, imp
war veraltet zugunsten importlib
. Wenn Sie auf 3 oder höher abzielen, verweisen Sie beim Aufrufen entweder auf das entsprechende Modul reload
oder importieren.
Ich denke, das ist, was Sie wollen. Webserver wie der Entwicklungsserver von Django verwenden dies, damit Sie die Auswirkungen Ihrer Codeänderungen sehen können, ohne den Serverprozess selbst neu zu starten.
Um aus den Dokumenten zu zitieren:
- Der Code des Python-Moduls wird neu kompiliert und der Code auf Modulebene erneut ausgeführt, wodurch ein neuer Satz von Objekten definiert wird, die durch Wiederverwendung von an Namen im Wörterbuch des Moduls gebunden werden Lader die das Modul ursprünglich geladen hat. Das
init
Funktion von Erweiterungsmodulen wird nicht ein zweites Mal aufgerufen.- Wie bei allen anderen Objekten in Python werden die alten Objekte erst zurückgefordert, nachdem ihre Referenzzähler auf Null gefallen sind.
- Die Namen im Modulnamensraum werden aktualisiert, um auf alle neuen oder geänderten Objekte zu verweisen.
- Andere Verweise auf die alten Objekte (z. B. Namen außerhalb des Moduls) werden nicht neu gebunden, um auf die neuen Objekte zu verweisen, und müssen in jedem Namensraum, in dem sie auftreten, aktualisiert werden, wenn dies gewünscht wird.
Wie Sie in Ihrer Frage angemerkt haben, müssen Sie rekonstruieren Foo
Objekte, wenn die Foo
Klasse wohnt in der foo
Modul.
Tatsächlich startet sich der Django-Dev-Server selbst neu, wenn Sie eine Datei ändern. (Er startet den Server neu, lädt nicht nur das Modul neu)
– Hasen
13. Januar 2009 um 6:36 Uhr
Woher kommt diese “is_changed”-Funktion? Ich sehe keine Dokumentation dazu und es läuft weder in meiner Python 3.1.3-Umgebung noch in 2.6.4.
– jedmao
17. Juni 2011 um 14:29 Uhr
no cdleary, Django kann nicht einfach reload verwenden: pyunit.sourceforge.net/notes/reloading.html
– Raylu
5. Oktober 2012 um 5:54 Uhr
reload reicht für Module mit Abhängigkeiten nicht aus. Siehe Bobince unten: stackoverflow.com/a/438845/456878. Das hat mich schon mal gebissen und gute 10 Minuten verschwendet.
– Doug Bradshaw
18. Februar 2015 um 13:59 Uhr
@jedmao @JamesDraper Ich bin mir ziemlich sicher is_changed
function ist nur eine willkürliche Funktion, die Sie schreiben müssten; es ist nicht eingebaut. Beispielsweise könnte es möglicherweise die Datei öffnen, die dem Modul entspricht, das Sie importieren, und es mit einer zwischengespeicherten Version vergleichen, um zu sehen, ob es sich geändert hat.
– James McGug
11. September 2018 um 14:38 Uhr
Paul D. Waite
In Python 3.0–3.3 würden Sie Folgendes verwenden: imp.reload(module)
Das BDFL hat antwortete diese Frage.
Jedoch, imp
wurde in 3.4 zugunsten von verworfen importlib
(Danke @Stefan!).
ich denkendaher würden Sie jetzt verwenden importlib.reload(module)
obwohl ich mir nicht sicher bin.
Der ernsthafte Neuling ist dankbar, etwas über kritische Nuancen zwischen Python 2 und 3 zu erfahren.
– Mandeloli
29. Juni 2010 um 21:26 Uhr
@LoïcFaure-Lacroix genauso reload(__builtins__)
ist gültig in 2.x
– JBernardo
20. Juni 2012 um 5:03 Uhr
@Tarrasch: Es ist das Python-Modul, das Sie neu laden möchten, wie im Beispiel in der Frage.
– Paul D. Waite
29. August 2013 um 9:17 Uhr
@LoïcFaure-Lacroix ja, Imp kann sich selbst neu laden.
– Devyn Collier Johnson
23. November 2013 um 22:34 Uhr
@PaulD.Waite, kann bestätigen, dass dies in Python 3.6.5 funktioniert
– aydow
7. Juni 2018 um 6:22 Uhr
Gregor Lind
Es kann besonders schwierig sein, ein Modul zu löschen, wenn es sich nicht um reines Python handelt.
Hier einige Informationen von: Wie lösche ich ein importiertes Modul wirklich?
Sie können sys.getrefcount() verwenden, um die tatsächliche Anzahl der Referenzen herauszufinden.
>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3
Zahlen größer als 3 zeigen an, dass es schwierig sein wird, das Modul loszuwerden. Das selbst erstellte “leere” (nichts enthaltende) Modul sollte danach von der Garbage Collection befreit werden
>>> del sys.modules["empty"]
>>> del empty
da die dritte Referenz ein Artefakt der Funktion getrefcount() ist.
Ich habe gerade entdeckt, dass Sie es auch dort löschen müssen, wenn das Modul Teil eines Pakets ist: setattr(package, "empty", None)
– u0b34a0f6ae
11. Mai 2010 um 12:33 Uhr
Dies ist die richtige Lösung, insbesondere wenn Sie ein Paket mit verschachtelten Modulen haben. reload()
lädt nur das oberste Modul neu, und alles darin enthaltene wird nicht neu geladen, es sei denn, Sie löschen es zuerst aus sys.modules.
– Cerin
5. Dezember 2016 um 20:05 Uhr
Bobine
reload(module)
, aber nur, wenn es komplett eigenständig ist. Wenn irgendetwas anderes einen Verweis auf das Modul (oder ein Objekt, das zum Modul gehört) hat, erhalten Sie subtile und merkwürdige Fehler, die dadurch verursacht werden, dass der alte Code länger herumhängt, als Sie erwartet haben, und ähnliches isinstance
funktioniert nicht über verschiedene Versionen desselben Codes hinweg.
Wenn Sie unidirektionale Abhängigkeiten haben, müssen Sie auch alle Module neu laden, die von dem neu geladenen Modul abhängen, um alle Verweise auf den alten Code loszuwerden. Und dann rekursiv Module neu laden, die von den neu geladenen Modulen abhängen.
Wenn Sie zirkuläre Abhängigkeiten haben, was zum Beispiel sehr häufig vorkommt, wenn Sie ein Paket neu laden, müssen Sie alle Module in der Gruppe auf einmal entladen. Das geht nicht mit reload()
da jedes Modul erneut importiert wird, bevor seine Abhängigkeiten aktualisiert wurden, wodurch alte Verweise in neue Module eingeschlichen werden können.
Die einzige Möglichkeit, dies in diesem Fall zu tun, ist zu hacken sys.modules
, was irgendwie nicht unterstützt wird. Sie müssten alle durchgehen und löschen sys.modules
Eintrag, den Sie beim nächsten Import neu laden wollten, und löschen Sie auch Einträge, deren Werte sind None
um ein Implementierungsproblem zu behandeln, das mit dem Zwischenspeichern fehlgeschlagener relativer Importe zu tun hat. Es ist nicht sehr schön, aber solange Sie einen vollständig in sich geschlossenen Satz von Abhängigkeiten haben, der keine Referenzen außerhalb seiner Codebasis hinterlässt, ist es praktikabel.
Es ist wahrscheinlich am besten, den Server neu zu starten. 🙂
goetzc
Für Python 2 Verwenden Sie die integrierte Funktion reload
:
reload(module)
Für Python 2 und Python 3.2—3.3 verwenden reload
aus Modul imp:
import imp
imp.reload(module)
Für Python ≥3.4, imp
ist veraltet zugunsten importlib
also benutze das:
import importlib
importlib.reload(module)
oder:
from importlib import reload
reload(module)
TL;DR:
Python ≥ 3.4: importlib.reload(module)
Python 3.2 – 3.3: imp.reload(module)
Python 2: reload(module)
um einen dieser Fälle zu behandeln: from six import reload_module
(müssen pip install six
zuerst natürlich)
– Anentrop
30. Oktober 2017 um 16:46 Uhr
@Anentropic: Es ist ein guter Rat, die Verwendung von Sechs-Paketen zu empfehlen, aber die Syntax ist es from six.moves import reload_module
(Dok)
– x0s
4. Januar 2018 um 20:32 Uhr
Daniel
if 'myModule' in sys.modules:
del sys.modules["myModule"]
um einen dieser Fälle zu behandeln: from six import reload_module
(müssen pip install six
zuerst natürlich)
– Anentrop
30. Oktober 2017 um 16:46 Uhr
@Anentropic: Es ist ein guter Rat, die Verwendung von Sechs-Paketen zu empfehlen, aber die Syntax ist es from six.moves import reload_module
(Dok)
– x0s
4. Januar 2018 um 20:32 Uhr
Matt Clarkson
Der folgende Code ermöglicht Ihnen die Kompatibilität mit Python 2/3:
try:
reload
except NameError:
# Python 3
from imp import reload
Sie können es als verwenden reload()
in beiden Versionen, was die Sache einfacher macht.
Memo-Tipp: “Importieren” bedeutet nicht “Laden”, sondern “Laden, wenn noch nicht geladen, und dann in den Namensraum importieren”.
– Kos
10. Januar 2013 um 11:30 Uhr
Die Frage sollte nicht “entladen” enthalten, da dies in Python noch nicht möglich ist – das Neuladen ist jedoch ein bekanntes Paradigma, wie unten beantwortet
– rjmoggach
29. Mai 2014 um 4:08 Uhr
Ich hatte das gleiche Problem bei der Verwendung eines dynamischen Moduls in der py2exe-App. Da py2exe Bytecode immer im Zip-Verzeichnis behielt, funktionierte das Neuladen nicht. Aber ich habe eine funktionierende Lösung mit dem Modul import_file gefunden. Jetzt funktioniert meine Anwendung einwandfrei.
– Pritam-Pfanne
5. März 2016 um 21:57 Uhr
Was ist, wenn Sie “entladen” möchten, weil der Versuch, eine .pyc-Datei zu löschen, vom Code verwendet wird?
– Dunkelblick
29. September 2016 um 13:48 Uhr