Ricarica sottomoduli in IPython


363

Attualmente sto lavorando a un progetto Python che contiene sottomoduli e utilizza numpy / scipy. Ipython è usato come console interattiva. Purtroppo non sono molto contento del flusso di lavoro che sto usando in questo momento, apprezzerei alcuni consigli.

In IPython, il framework viene caricato da un semplice importcomando. Tuttavia, è spesso necessario modificare il codice in uno dei sottomoduli del framework. A questo punto un modello è già caricato e utilizzo IPython per interagire con esso.

Ora, il framework contiene molti moduli che dipendono l'uno dall'altro, cioè quando il framework viene inizialmente caricato il modulo principale sta importando e configurando i sottomoduli. Le modifiche al codice vengono eseguite solo se il modulo viene ricaricato utilizzando reload(main_mod.sub_mod). Questo è complicato poiché devo ricaricare tutti i moduli modificati individualmente usando il percorso completo. Sarebbe molto conveniente reload(main_module)ricaricare anche tutti i moduli secondari, ma senza ricaricare numpy / scipy.


Ti andrebbe di approfondire di più However, it is often necessary to change code in one of the submodules of the framework.Quindi perché necessary to change code? Grazie
mangia il

16
@eat: il framework viene continuamente sviluppato, quindi ci sono continue modifiche alla base di codice.
Alain,

Risposte:


531

IPython viene fornito con un po ' di magia di ricarica automatica :

%load_ext autoreload
%autoreload 2

Ricaricherà tutti i moduli modificati ogni volta prima di eseguire una nuova linea. Il modo in cui funziona è leggermente diverso da dreload. Si applicano alcuni avvertimenti, digitare %autoreload?per vedere cosa può andare storto.


Se si desidera abilitare sempre queste impostazioni, modificare il file di configurazione di IPython ~/.ipython/profile_default/ipython_config.py[1] e aggiungere:

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

Ringraziamo @Kos tramite un commento qui sotto.

[1] Se non hai il file ~/.ipython/profile_default/ipython_config.py, devi ipython profile createprima chiamare . Oppure il file può trovarsi in $IPYTHONDIR.


63
Ho c.InteractiveShellApp.extensions = ['autoreload']e c.InteractiveShellApp.exec_lines = ['%autoreload 2']nel mio ~/.ipython/profile_default/ipython_config.py.
Kos,

4
Potrebbe essere un successo, tuttavia, usa con cautela.
asmeurer

3
Il ricaricamento viene eseguito solo quando si preme Invio nella shell Ipython e di solito non si nota.
pv.

3
Funziona abbastanza bene durante il debug dei pacchetti, quindi qual è lo scopo del caricamento, sembra che il caricamento sia troppo invasivo e stampa errori quando vengono caricati alcuni pacchetti come matplotlib.
dashesy,

3
Se si utilizza il metodo @Kos, assicurarsi che sia definito c: c = get_config ()
Tickon

27

In IPython 0.12 (e possibilmente in precedenza), puoi usare questo:

%load_ext autoreload
%autoreload 2

Questa è essenzialmente la stessa della risposta di pv. , tranne per il fatto che l'estensione è stata rinominata e ora viene caricata con %load_ext.


20

Per qualche motivo, né %autoreload, né dreloadsembra funzionare per la situazione quando si importa il codice da un notebook all'altro . reloadFunziona solo in Python :

reload(module)

Basato su [1] .


10
In Python 3.4+, puoi trovare ricaricare nel modulo importlib. Vedere questa domanda .
Praveen,

1
Questo metodo funziona quando si aggiunge un metodo di istanza, a differenza della %autoreloadtecnica. C'è una segnalazione di bug aperta a cui aggiungere supporto %autoreloadper questo. .
ijoseph,

18

IPython offre dreload()di ricaricare ricorsivamente tutti i sottomoduli. Personalmente, preferisco usare il %run()comando magico (anche se non esegue una ricarica profonda, come sottolineato da John Salvatier nei commenti).


11
Penso che (sfortunatamente)% esegua script.py ricarica solo lo script che stai chiamando, non i pacchetti che importa. Se stai cercando di eseguire il debug di un pacchetto che stai creando, questo può essere un problema.
John Salvatier,

2
NB. dreloadè stato sostituito in recente IPython (ad esempio IPython 6.0) da deepreload .
dan mackinlay,

8

Il modulo denominato importlibconsente di accedere agli interni di importazione. In particolare, fornisce la funzione importlib.reload():

import importlib
importlib.reload(my_module)

Al contrario %autoreload, importlib.reload()reimpostare anche le variabili globali impostate nel modulo. Nella maggior parte dei casi, è quello che vuoi.

importlibè disponibile solo da Python 3.1. Per la versione precedente, è necessario utilizzare il modulo imp.


unica soluzione che ha funzionato per me
gustavz

5

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

Per evitare di digitare ripetutamente quelle funzioni magiche, potrebbero essere inserite nello script di avvio di ipython (denominalo con il suffisso .py sotto .ipython / profilo_default / startup. Tutti gli script di Python in quella cartella verranno caricati in base all'ordine lessicale), che è simile al seguente:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")

Questo sembra funzionare anche se stai eseguendo il tuo script con ad es. %run script.pyDa IPython REPL
Patrick Sanan,

3

Cosa ne pensi di questo:

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

Questo dovrebbe ricaricare efficacemente l'intero albero di moduli e sottomoduli che gli dai. Puoi anche inserire questa funzione nel tuo .ipythonrc (penso) in modo che venga caricata ogni volta che avvii l'interprete.


Ciò sembra buono, tuttavia, potrebbe non riguardare moduli o membri di moduli importati utilizzando from ... import ...o import ... as. Almeno questo mi dà spesso qualche problema quando lavoro in modo interattivo sul terminale. Sono passato a utilizzare le macro memorizzate in IPython che eseguono le importazioni e le impostazioni necessarie per iniziare a lavorare in uno stato predefinito.
Bernhard

In realtà copre from ... import ...e import ... asfintanto che la cosa che hai importato è un modulo. L'unica cosa che non copre sono i moduli in un pacchetto che non sono stati caricati dal suo __init__.pyfile. Per i pacchetti, puoi probabilmente verificare se l' __path__attributo del modulo è una directory. In tal caso, attraversalo e importa in modo ricorsivo tutti i moduli che potresti trovare. Non ho scritto questa parte perché l'autore non ha richiesto una soluzione per i pacchetti.
YH Wong,

In effetti questo sembra buono. Ho pensato a questa possibilità, allo stesso tempo mi sarei aspettato che ci fossero alcune funzionalità integrate, cioè basate su questo . Tuttavia, non mi era chiaro come usarlo. Dopo alcuni scavi che avrebbero dovuto verificarsi prima di pubblicare la domanda originale, ho trovato questa estensione .
Alain,

Inoltre è possibile utilizzare pkgutilper ottenere tutti i sottomoduli in un pacchetto, anche se il pacchetto non importa i sottomoduli nel modulo superiore. stackoverflow.com/a/1707786/1243926
osa

devi anche fare: per il modulo insys.modules:
aoeu256,

2

Un'altra opzione:

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

Verificato su ipython e ipython3 v5.1.0 su Ubuntu 14.04.


1

La mia pratica standard per ricaricare è combinare entrambi i metodi dopo la prima apertura di IPython:

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

Se si caricano moduli prima di farlo, si eviterà che vengano ricaricati, anche con un manuale reload(module_name). Molto raramente ho ancora problemi inspiegabili con metodi di classe che non si ricaricano e che non ho ancora esaminato.


1

Si noti che quanto sopra autoreloadfunziona solo in IntelliJ se si salva manualmente il file modificato (ad es. Usando ctrl + so cmd + s). Non sembra funzionare con il salvataggio automatico.


Confermo che questo vale anche per PyCharm.
Tsando,

0

Sui quaderni di Jupyter su Anaconda, facendo questo:

%load_ext autoreload
%autoreload 2

prodotto il messaggio:

L'estensione di caricamento automatico è già caricata. Per ricaricarlo, utilizzare: %reload_ext autoreload

Sembra che sia preferibile fare:

%reload_ext autoreload
%autoreload 2

Informazioni sulla versione:

La versione del server notebook è 5.0.0 ed è in esecuzione su: Python 3.6.2 | Anaconda, Inc. | (impostazione predefinita, 20 settembre 2017, 13:35:58) [MSC v.1900 32 bit (Intel)]


0

Qualsiasi oggetto secondario non verrà ricaricato da questo, credo che per questo sia necessario utilizzare il deepreload di IPython.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.