Submodule in IPython neu laden

363

Derzeit arbeite ich an einem Python-Projekt, das Submodule enthält und numpy / scipy verwendet. Ipython wird als interaktive Konsole verwendet. Leider bin ich mit dem Workflow, den ich gerade verwende, nicht sehr zufrieden. Ich würde mich über einige Ratschläge freuen.

In IPython wird das Framework durch einen einfachen importBefehl geladen . Es ist jedoch häufig erforderlich, Code in einem der Submodule des Frameworks zu ändern. Zu diesem Zeitpunkt ist bereits ein Modell geladen und ich verwende IPython, um mit ihm zu interagieren.

Jetzt enthält das Framework viele Module, die voneinander abhängen, dh wenn das Framework zum ersten Mal geladen wird, importiert und konfiguriert das Hauptmodul die Submodule. Die Änderungen am Code werden nur ausgeführt, wenn das Modul mit neu geladen wird reload(main_mod.sub_mod). Dies ist umständlich, da ich alle geänderten Module einzeln über den vollständigen Pfad neu laden muss. Es wäre sehr praktisch, wenn reload(main_module)auch alle Submodule neu geladen würden, ohne jedoch numpy / scipy neu zu laden.

Alain
quelle
Möchten Sie mehr darüber However, it is often necessary to change code in one of the submodules of the framework.erfahren necessary to change code? Warum also ? Danke
essen
16
@eat: Das Framework wird ständig weiterentwickelt, daher ändert sich die Codebasis ständig.
Alain

Antworten:

531

IPython bietet eine automatische Magie zum Nachladen :

%load_ext autoreload
%autoreload 2

Alle geänderten Module werden jedes Mal neu geladen, bevor eine neue Zeile ausgeführt wird. Die Art und Weise, wie dies funktioniert, ist etwas anders als dreload. Es gelten einige Einschränkungen. Geben Sie ein, um %autoreload?zu sehen, was schief gehen kann.


Wenn Sie diese Einstellungen immer aktivieren möchten, ändern Sie Ihre IPython-Konfigurationsdatei ~/.ipython/profile_default/ipython_config.py[1] und fügen Sie Folgendes hinzu:

c.InteractiveShellApp.extensions = ['autoreload']     
c.InteractiveShellApp.exec_lines = ['%autoreload 2']

Gutschrift an @Kos über einen Kommentar unten.

[1] Wenn Sie die Datei nicht haben ~/.ipython/profile_default/ipython_config.py, müssen Sie ipython profile createzuerst anrufen . Oder die Datei befindet sich unter $IPYTHONDIR.

pv.
quelle
63
Ich habe c.InteractiveShellApp.extensions = ['autoreload']und c.InteractiveShellApp.exec_lines = ['%autoreload 2']in meinem ~/.ipython/profile_default/ipython_config.py.
Kos
4
Dies könnte jedoch ein Leistungseinbruch sein. Gehen Sie daher vorsichtig vor.
Asmeurer
3
Das Neuladen wird nur ausgeführt, wenn Sie in der Ipython-Shell die Eingabetaste drücken, und ist normalerweise nicht erkennbar.
pv.
3
Dies funktioniert ziemlich gut beim Debuggen von Paketen. Was also der Zweck von Dreload ist, scheint Dreload zu invasiv zu sein und gibt Fehler aus, wenn einige Pakete wie matplotlib geladen werden.
Bindestrich
3
Wenn Sie die @ Kos-Methode verwenden, stellen Sie sicher, dass c definiert ist: c = get_config ()
Tickon
27

In IPython 0.12 (und möglicherweise früher) können Sie Folgendes verwenden:

%load_ext autoreload
%autoreload 2

Dies entspricht im Wesentlichen der Antwort von pv. , außer dass die Erweiterung umbenannt wurde und jetzt mit geladen wird %load_ext.

RafG
quelle
20

Aus irgendeinem Grund scheint es für die Situation, in der Sie Code von einem Notizbuch in ein anderes importieren , weder zu funktionieren %autoreloadnoch dreloadzu funktionieren . Nur einfaches Python funktioniert:reload

reload(module)

Basierend auf [1] .

Dennis Golomazov
quelle
10
In Python 3.4+ finden Sie reload im importlib-Modul. Siehe diese Frage .
Praveen
1
Diese Methode funktioniert im Gegensatz zur %autoreloadTechnik beim Hinzufügen einer Instanzmethode . Es gibt einen offenen Fehlerbericht, der %autoreloaddiesbezüglich Unterstützung bietet. .
Ijoseph
18

IPython bietet dreload()an, alle Submodule rekursiv neu zu laden. Persönlich bevorzuge ich die Verwendung des %run()magischen Befehls (obwohl er kein tiefes Nachladen durchführt, wie John Salvatier in den Kommentaren hervorhob).

Sven Marnach
quelle
11
Ich denke, dass (leider)% run script.py nur das Skript neu lädt, das Sie aufrufen, nicht die Pakete, die es importiert. Wenn Sie versuchen, ein Paket zu debuggen, das Sie erstellen, kann dies schmerzhaft sein.
John Salvatier
2
NB. dreloadwurde in IPython (z. B. IPython 6.0) durch deepreload ersetzt .
Dan Mackinlay
8

Das Modul mit dem Namen importlibermöglicht den Zugriff auf Import-Interna. Insbesondere bietet es Funktion importlib.reload():

import importlib
importlib.reload(my_module)

Im Gegenteil %autoreload, importlib.reload()auch zurückgesetzt global in Modul gesetzt Variablen. In den meisten Fällen ist es das, was Sie wollen.

importlibist nur seit Python 3.1 verfügbar. Für ältere Versionen müssen Sie Modul verwenden imp.

Jérôme Pouiller
quelle
einzige Lösung, die für mich funktioniert hat
gustavz
5

http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/

Um zu vermeiden, dass diese magische Funktion immer wieder eingegeben wird, können sie in das ipython-Startskript eingefügt werden (benennen Sie es mit dem Suffix .py unter .ipython / profile_default / startup. Alle Python-Skripte unter diesem Ordner werden in lexikalischer Reihenfolge geladen) sieht wie folgt aus:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")
Pegasus
quelle
Dies scheint auch zu funktionieren, wenn Sie Ihr Skript zB mit %run script.pyIPython REPL ausführen
Patrick Sanan
3

Wie wäre es damit:

import inspect

# needs to be primed with an empty set for loaded
def recursively_reload_all_submodules(module, loaded=None):
    for name in dir(module):
        member = getattr(module, name)
        if inspect.ismodule(member) and member not in loaded:
            recursively_reload_all_submodules(member, loaded)
    loaded.add(module)
    reload(module)

import mymodule
recursively_reload_all_submodules(mymodule, set())

Dadurch sollte der gesamte Baum der Module und Submodule, die Sie ihm geben, effektiv neu geladen werden. Sie können diese Funktion auch in Ihre .ipythonrc einfügen (glaube ich), damit sie jedes Mal geladen wird, wenn Sie den Interpreter starten.

YH Wong
quelle
Das sieht gut aus, es kann jedoch sein, dass es keine Module oder Mitglieder von Modulen abdeckt, die mit from ... import ...oder importiert werden import ... as. Zumindest bereitet mir das oft Probleme, wenn ich interaktiv am Terminal arbeite. Ich habe gespeicherte Makros in IPython verwendet, die die erforderlichen Importe und Setups ausführen, um in einem vordefinierten Zustand zu arbeiten.
Bernhard
Es deckt tatsächlich ab from ... import ...und import ... assolange das, was Sie importiert haben, ein Modul ist. Das einzige, was nicht behandelt wird, sind Module in einem Paket, die nicht aus der __init__.pyDatei geladen wurden . Bei Paketen können Sie wahrscheinlich überprüfen, ob das __path__Attribut des Moduls ein Verzeichnis ist. Wenn dies der Fall ist, durchlaufen Sie es und importieren Sie rekursiv alle Module, die Sie finden konnten. Ich habe diesen Teil nicht geschrieben, weil der Autor nicht nach einer Lösung für Pakete gefragt hat.
YH Wong
In der Tat sieht das gut aus. Ich dachte über diese Möglichkeit nach, gleichzeitig würde ich erwarten, dass es einige eingebaute Funktionen geben würde, dh basierend darauf . Mir war jedoch nicht klar, wie ich das verwenden sollte. Nach einigem Graben, das hätte stattfinden sollen, bevor ich die ursprüngliche Frage gestellt habe, habe ich diese Erweiterung gefunden .
Alain
Sie können auch pkgutilalle Submodule in einem Paket abrufen, auch wenn das Paket die Submodule nicht in das oberste Modul importiert. stackoverflow.com/a/1707786/1243926
osa
Sie müssen auch tun: für Modul in sys.modules:
aoeu256
2

Andere Option:

$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF

Verifiziert unter ipython und ipython3 v5.1.0 unter Ubuntu 14.04.

Tschad
quelle
1

Meine Standardpraxis für das Nachladen besteht darin, beide Methoden nach dem ersten Öffnen von zu kombinieren IPython:

from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2

Wenn Sie zuvor Module laden, werden diese auch mit einem Handbuch nicht neu geladen reload(module_name). Ich bekomme immer noch sehr selten unerklärliche Probleme mit Klassenmethoden, die nicht neu geladen werden und die ich noch nicht untersucht habe.

Ryanjdillon
quelle
1

Beachten Sie, dass das oben Genannte autoreloadin IntelliJ nur funktioniert, wenn Sie die geänderte Datei manuell speichern (z. B. mit Strg + s oder cmd + s). Es scheint nicht mit automatischem Speichern zu funktionieren.

Hubert Grzeskowiak
quelle
Ich bestätige, dass dies auch für PyCharm der Fall ist.
Tsando
0

Auf Jupyter Notebooks auf Anaconda gehen Sie folgendermaßen vor:

%load_ext autoreload
%autoreload 2

produzierte die Nachricht:

Die Autoreload-Erweiterung ist bereits geladen. Verwenden Sie zum erneuten Laden Folgendes: %reload_ext autoreload

Es sieht so aus, als wäre es vorzuziehen:

%reload_ext autoreload
%autoreload 2

Versionsinformation:

Die Version des Notebook-Servers ist 5.0.0 und läuft unter: Python 3.6.2 | Anaconda, Inc. | (Standard, 20. September 2017, 13:35:58) [MSC v.1900 32 Bit (Intel)]

Danke im Voraus
quelle
0

Unterobjekte werden dadurch nicht neu geladen. Ich glaube, Sie müssen dafür IPythons Deepreload verwenden.

aoeu256
quelle