1118 Stimmen

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

Ich habe einen seit langem laufenden Python-Server und möchte einen Dienst aktualisieren können, ohne den Server neu zu starten. Wie kann ich das am besten machen?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()

1146voto

cdleary Punkte 66512

Sie können ein Modul neu laden, wenn es bereits importiert wurde, indem Sie importlib.reload() :

from importlib import reload  # Python 3.4+
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

In Python 2, reload war ein Built-in. In Python 3 war es umgezogen zum imp Modul. In 3.4, imp war Abgelehnt zugunsten von importlib . Wenn Sie auf 3 oder höher zielen, verweisen Sie entweder auf das entsprechende Modul, wenn Sie reload oder importieren Sie sie.

Ich glaube, das ist es, 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 Unterlagen zu zitieren:

  • Der Code des Python-Moduls wird neu kompiliert und der Code auf Modulebene wird erneut ausgeführt, wobei eine neue Gruppe von Objekten definiert wird, die an Namen im Wörterbuch des Moduls gebunden sind, indem die Lader die das Modul ursprünglich geladen hat. Die init Funktion von Erweiterungsmodulen wird nicht ein zweites Mal aufgerufen.
  • Wie bei allen anderen Objekten in Python werden die alten Objekte erst dann zurückgewonnen, wenn die Anzahl ihrer Referenzen auf Null gesunken ist.
  • Die Namen im Modul-Namensraum werden aktualisiert, um auf neue oder geänderte Objekte zu verweisen.
  • Andere Verweise auf die alten Objekte (z. B. Namen außerhalb des Moduls) werden nicht auf die neuen Objekte zurückgeführt und müssen in jedem Namensraum, in dem sie vorkommen, aktualisiert werden, wenn dies gewünscht ist.

Wie Sie in Ihrer Frage anmerkten, müssen Sie die Daten rekonstruieren. Foo Objekte, wenn die Foo Klasse befindet sich in der foo module.

280voto

Paul D. Waite Punkte 92952

In Python 3.0-3.3 würden Sie verwenden: imp.reload(module)

El BDFL hat antwortete diese Frage.

Allerdings, imp wurde in 3.4 veraltet, zugunsten von importlib (Dank @Stefan! ).

I denken Daher würden Sie jetzt Folgendes verwenden importlib.reload(module) Ich bin mir allerdings nicht sicher.

136voto

Gregg Lind Punkte 19744

Es kann besonders schwierig sein, ein Modul zu löschen, wenn es sich nicht um reines Python handelt.

Hier sind einige Informationen von: Wie kann ich ein importiertes Modul wirklich löschen?

Sie können sys.getrefcount() verwenden, um die tatsächliche Anzahl der Referenzen zu erfahren.

import sys, empty, os sys.getrefcount(sys) 9 sys.getrefcount(os) 6 sys.getrefcount(empty) 3

Zahlen größer als 3 bedeuten, dass es schwer sein wird, das Modul loszuwerden Modul. Das selbstentwickelte "leere" (nichts enthaltend) Modul sollte sein Garbage Collect nach

del sys.modules["empty"] del empty

da die dritte Referenz ein Artefakt ist der Funktion getrefcount().

101voto

bobince Punkte 512550

reload(module) aber nur, wenn sie völlig eigenständig ist. Wenn irgendetwas anderes einen Verweis auf das Modul (oder ein zum Modul gehörendes Objekt) hat, dann werden Sie subtile und merkwürdige Fehler erhalten, die dadurch verursacht werden, dass der alte Code länger als erwartet herumhängt, und Dinge wie isinstance nicht über verschiedene Versionen desselben Codes hinweg funktioniert.

Wenn Sie einseitige 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 zu entfernen. Und dann laden Sie die Module, die von den neu geladenen Modulen abhängen, rekursiv neu.

Wenn Sie zirkuläre Abhängigkeiten haben, was z. B. beim Nachladen eines Pakets sehr häufig vorkommt, müssen Sie alle Module der Gruppe in einem Zug entladen. Sie können dies nicht tun mit reload() weil es jedes Modul neu importiert, bevor seine Abhängigkeiten aktualisiert wurden, wodurch sich alte Referenzen in neue Module einschleichen können.

Die einzige Möglichkeit, dies zu tun, besteht darin, Folgendes zu hacken sys.modules was irgendwie nicht unterstützt wird. Sie müssten durchgehen und jede einzelne Datei löschen. sys.modules Eintrag, der beim nächsten Import neu geladen werden soll, und löschen Sie auch Einträge, deren Werte None um ein Implementierungsproblem zu lösen, das mit der Zwischenspeicherung fehlgeschlagener relativer Importe zu tun hat. Es ist nicht sonderlich schön, aber solange man einen vollständig in sich geschlossenen Satz von Abhängigkeiten hat, der keine Referenzen außerhalb seiner Codebasis hinterlässt, ist es machbar.

Es ist wahrscheinlich am besten, den Server neu zu starten :-)

88voto

goetzc Punkte 1756

Für Python 2 eingebaute Funktion verwenden reload :

reload(module)

Für Python 2 y Python 3.2 - 3.3 verwenden. reload vom Modul imp :

import imp
imp.reload(module)

Für Python 3.4 , imp ist veraltet zugunsten von importlib also verwenden Sie dies:

import importlib
importlib.reload(module)

o:

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)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X