Wie kann ich ein Python-Modul entladen (neu laden)?

Lesezeit: 7 Minuten

Benutzer-Avatar
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()

  • 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

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

Benutzer-Avatar
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

Benutzer-Avatar
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

Benutzer-Avatar
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. 🙂

Benutzer-Avatar
goetzc

Für Python 2 Verwenden Sie die integrierte Funktion reload:

reload(module)

Für Python 2 und Python 3.23.3 verwenden reload aus Modul imp:

import imp
imp.reload(module)

Für Python ≥3.4, imp ist veraltet zugunsten importlibalso 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

Benutzer-Avatar
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

Benutzer-Avatar
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.

1146390cookie-checkWie kann ich ein Python-Modul entladen (neu laden)?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy