Come faccio a scaricare (ricaricare) un modulo?
Ho un server Python in funzione da molto tempo e vorrei essere in grado di aggiornare un servizio senza riavviare il server. Qual è il modo migliore per farlo?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
756
3
Puoi ricaricare un modulo quando è già stato importato usando la funzione integrata
reload
:In Python 3,
reload
è stato spostato nel moduloimp
. In 3.4,imp
è stato deprecato in favore diimportlib
, ereload
è stato aggiunto a quest'ultimo. Quando si punta alla 3 o alle versioni successive, o si fa riferimento al modulo appropriato quando si chiamareload
o lo si importa.Penso che questo sia ciò che vuoi. I server web come il server di sviluppo di Django lo usano in modo da poter vedere gli effetti delle tue modifiche al codice senza riavviare il processo del server stesso.
Per citare dalla documentazione:
Come hai notato nella tua domanda, dovrai ricostruire gli oggetti
Foo
se la classeFoo
risiede nel modulofoo
.Può essere particolarmente difficile cancellare un modulo se non è Python puro.
Ecco alcune informazioni tratte da: Come faccio a cancellare veramente un modulo importato?
Potete usare sys.getrefcount() per scoprire il numero effettivo di riferimenti.
reload(module)
, ma solo se è completamente indipendente. Se qualcos'altro ha un riferimento al modulo (o qualsiasi oggetto appartenente al modulo), allora otterrete errori sottili e curiosi causati dal vecchio codice che rimane in giro più a lungo di quanto vi aspettavate, e cose comeisinstance
non funzionano tra diverse versioni dello stesso codice.Se hai dipendenze unidirezionali, devi anche ricaricare tutti i moduli che dipendono dal modulo ricaricato per liberarti di tutti i riferimenti al vecchio codice. E poi ricaricare i moduli che dipendono dai moduli ricaricati, ricorsivamente.
Se avete dipendenze circolari, che è molto comune per esempio quando si tratta di ricaricare un pacchetto, dovete scaricare tutti i moduli del gruppo in una volta sola. Non puoi farlo con
reload()
perché reimporterà ogni modulo prima che le sue dipendenze siano state aggiornate, permettendo ai vecchi riferimenti di insinuarsi nei nuovi moduli.L'unico modo per farlo in questo caso è quello di hackerare
sys.modules
, che non è supportato. Dovresti passare attraverso e cancellare ogni voce disys.modules
che vuoi che sia ricaricata alla prossima importazione, e anche cancellare le voci i cui valori sonoNone
per affrontare un problema di implementazione che ha a che fare con il caching delle importazioni relative fallite. Non è terribilmente bello, ma finché si ha un insieme di dipendenze completamente autonomo che non lascia riferimenti al di fuori della sua base di codice, è fattibile.Probabilmente è meglio riavviare il server.)