Come scarico (ricarica) un modulo Python?

Translate

Ho un server Python di lunga durata 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()
This question and all comments follow the "Attribution Required."

Tutte le risposte

Translate

È possibile ricaricare un modulo quando è già stato importato utilizzando il filereloadfunzione incorporata:

from importlib import reload  # Python 3.4+ only.
import foo

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

In Python 3,reloadè stato spostato inimpmodulo. In 3.4,impè stato deprecato a favore diimportlib, ereloada quest'ultimo si è aggiunto. Quando scegli come target 3 o versioni successive, fai riferimento al modulo appropriato durante la chiamatareloado importalo.

Penso che questo sia quello che vuoi. I server Web come il server di sviluppo di Django lo utilizzano in modo da poter vedere gli effetti delle modifiche al codice senza riavviare il processo del server stesso.

Per citare dai documenti:

Il codice dei moduli Python viene ricompilato e il codice a livello di modulo viene rieseguito, definendo un nuovo insieme di oggetti che sono legati ai nomi nel dizionario del modulo. La funzione init dei moduli di estensione non viene chiamata una seconda volta. Come con tutti gli altri oggetti in Python, i vecchi oggetti vengono recuperati solo dopo che i loro conteggi di riferimento sono scesi a zero. I nomi nello spazio dei nomi del modulo vengono aggiornati per puntare a qualsiasi oggetto nuovo o modificato. Altri riferimenti ai vecchi oggetti (come i nomi esterni al modulo) non vengono rimandati ai nuovi oggetti e devono essere aggiornati in ogni spazio dei nomi in cui si verificano, se lo si desidera.

Come hai notato nella tua domanda, dovrai ricostruireFoooggetti se il fileFoola classe risiede infoomodulo.

fonte
Translate

In Python 3.0–3.3 useresti:imp.reload(module)

IlBDFLhaha rispostoquesta domanda.

Però,impè stato deprecato in 3.4, a favore diimportlib(Grazie@Stefan!).

I pensare, quindi, ora userestiimportlib.reload(module), anche se non ne sono sicuro.

fonte
Translate

Può essere particolarmente difficile eliminare un modulo se non è puro Python.

Ecco alcune informazioni da:Come si elimina davvero un modulo importato?

Puoi usare sys.getrefcount () per scoprire il numero effettivo di riferimenti.

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

I numeri maggiori di 3 indicano che sarà difficile sbarazzarsi del modulo. Il modulo "vuoto" (che non contiene nulla) locale dovrebbe essere raccolto dopo

>>> del sys.modules["empty"]
>>> del empty

poiché il terzo riferimento è un artefatto della funzione getrefcount ().

fonte
Translate

reload(module), ma solo se è completamente autonomo. Se qualcos'altro ha un riferimento al modulo (o qualsiasi oggetto appartenente al modulo), riceverai errori sottili e curiosi causati dal vecchio codice in giro più a lungo di quanto ti aspettassi, e cose comeisinstancenon funziona su versioni diverse dello stesso codice.

Se hai dipendenze unidirezionali, devi anche ricaricare tutti i moduli che dipendono dal modulo ricaricato per eliminare tutti i riferimenti al vecchio codice. Quindi ricaricare i moduli che dipendono dai moduli ricaricati, in modo ricorsivo.

Se hai dipendenze circolari, cosa molto comune ad esempio quando hai a che fare con il ricaricamento di un pacchetto, devi scaricare tutti i moduli del gruppo in una volta sola. Non puoi farlo conreload()perché reimporterà ogni modulo prima che le sue dipendenze siano state aggiornate, consentendo ai vecchi riferimenti di insinuarsi in nuovi moduli.

L'unico modo per farlo in questo caso è hackeraresys.modules, che è un po 'non supportato. Dovresti passare attraverso ed eliminare ciascunosys.modulesvoce che si desiderava ricaricare alla successiva importazione e inoltre eliminare le voci i cui valori sonoNoneper affrontare un problema di implementazione relativo alla memorizzazione nella cache delle importazioni relative non riuscite. Non è molto carino, ma fintanto che si dispone di un set di dipendenze completamente autonomo che non lascia riferimenti al di fuori della propria base di codice, è funzionante.

Probabilmente è meglio riavviare il server. :-)

fonte
Translate
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
fonte
Translate

Per Python 2 usa la funzione incorporataricaricare():

reload(module)

Per Python 2 e 3.2-3.3 utilizzarericaricare dal modulo imp:

import imp
imp.reload(module)

Maimp è deprecatodalla versione 3.4a favore di importlib, quindi usa:

import importlib
importlib.reload(module)

or

from importlib import reload
reload(module)
fonte
Translate

Il codice seguente consente la compatibilità con Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

Puoi usarlo comereload()in entrambe le versioni che rende le cose più semplici.

fonte
Translate

La risposta accettata non gestisce il caso Y importato da X. Questo codice lo gestisce e anche il caso di importazione standard:

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

Nel caso del ricaricamento, riassegniamo i nomi di livello superiore ai valori memorizzati nel modulo appena ricaricato, che li aggiorna.

fonte
Translate

Questo è il modo moderno per ricaricare un modulo:

from importlib import reload

Se vuoi supportare versioni di Python precedenti alla 3.4, prova questo:

from sys import version_info
if version_info[0] < 3:
    pass # Python 2 has built in reload
elif version_info[0] == 3 and version_info[1] <= 4:
    from imp import reload # Python 3.0 - 3.4 
else:
    from importlib import reload # Python 3.5+

Per usarlo, corrireload(MODULE), sostituendoMODULEcon il modulo che vuoi ricaricare.

Per esempio,reload(math)ricaricherà il filemathmodulo.

fonte
Translate

Se seinonin un server, masviluppandoe devi ricaricare frequentemente un modulo, ecco un bel suggerimento.

Innanzitutto, assicurati di utilizzare l'eccellenteShell IPython, dal progetto Jupyter Notebook. Dopo aver installato Jupyter, puoi avviarlo conipython, ojupyter console, o anche meglio,jupyter qtconsole, che ti darà una bella console colorata con completamento del codice in qualsiasi sistema operativo.

Ora nella tua shell, digita:

%load_ext autoreload
%autoreload 2

Adesso,ogni voltaesegui il tuo script, i tuoi moduli verranno ricaricati.

Oltre il2, ci sono altriopzioni della magia di caricamento automatico:

%autoreload
Reload all modules (except those excluded by %aimport) automatically now.

%autoreload 0
Disable automatic reloading.

%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.

%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.
fonte
Enoch Lee
Translate

Per quelli come me che vogliono scaricare tutti i moduli (durante l'esecuzione nell'interprete Python sottoEmacs):

   for mod in sys.modules.values():
      reload(mod)

Ulteriori informazioni sono disponibiliRicaricamento dei moduli Python.

fonte
Translate

En Thought Traits ha un modulo che funziona abbastanza bene per questo.https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Ricaricherà qualsiasi modulo che è stato modificato e aggiornerà altri moduli e oggetti istanziati che lo stanno utilizzando. Non funziona la maggior parte delle volte con__very_private__metodi e può soffocare sull'ereditarietà della classe, ma mi fa risparmiare una quantità enorme di tempo dal dover riavviare l'applicazione host durante la scrittura di PyQt guis o cose che vengono eseguite all'interno di programmi come Maya o Nuke. Non funziona forse il 20-30% delle volte, ma è comunque incredibilmente utile.

Il pacchetto di En Thought non ricarica i file nel momento in cui cambiano - devi chiamarlo esplicitamente - ma non dovrebbe essere così difficile da implementare se ne hai davvero bisogno

fonte
Translate

Coloro che usano python 3 e ricaricano da importlib.

Se hai problemi come sembra che il modulo non si ricarichi ... Questo perché ha bisogno di un po 'di tempo per ricompilare pyc (fino a 60 sec). Scrivo questo suggerimento solo per sapere se hai riscontrato questo tipo di problema.

fonte
Translate

2018-02-01

  1. modulofoodeve essere importato con successo in anticipo.
  2. from importlib import reload, reload(foo)

31.5. importlib - L'implementazione di import - Documentazione Python 3.6.4

fonte
Translate

Altra opzione. Vedi quell'impostazione predefinita di Pythonimportlib.reloadreimporterà semplicemente la libreria passata come argomento. Itnon lo faròricarica le librerie importate dalla tua lib. Se hai modificato molti file e hai un pacchetto piuttosto complesso da importare, devi eseguire un filericarica profonda.

Se haiIPythonoJupyterinstallato, è possibile utilizzare una funzione per ricaricare in profondità tutte le librerie:

from IPython.lib.deepreload import reload as dreload
dreload(foo)

Se non hai Jupyter, installalo con questo comando nella tua shell:

pip3 install jupyter
fonte
Translate

per me per il caso di Abaqus è il modo in cui funziona. Immagina che il tuo file sia Class_VerticesEdges.py

sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:  
    del sys.modules['Class_VerticesEdges']
    print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])
fonte
Translate

Un altro modo potrebbe essere importare il modulo in una funzione. In questo modo, quando la funzione viene completata, il modulo ottiene la raccolta dei rifiuti.

fonte
Translate

Ho avuto molti problemi nel provare a ricaricare qualcosa in Sublime Text, ma finalmente ho potuto scrivere questa utility per ricaricare i moduli su Sublime Text in base al codicesublime_plugin.pyutilizza per ricaricare i moduli.

Ciò di seguito accetta di ricaricare i moduli da percorsi con spazi sui loro nomi, quindi in seguito, dopo il ricaricamento, puoi semplicemente importarli come fai di solito.

def reload_module(full_module_name):
    """
        Assuming the folder `full_module_name` is a folder inside some
        folder on the python sys.path, for example, sys.path as `C:/`, and
        you are inside the folder `C:/Path With Spaces` on the file 
        `C:/Path With Spaces/main.py` and want to re-import some files on
        the folder `C:/Path With Spaces/tests`

        @param full_module_name   the relative full path to the module file
                                  you want to reload from a folder on the
                                  python `sys.path`
    """
    import imp
    import sys
    import importlib

    if full_module_name in sys.modules:
        module_object = sys.modules[full_module_name]
        module_object = imp.reload( module_object )

    else:
        importlib.import_module( full_module_name )

def run_tests():
    print( "\n\n" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )

    from .tests import semantic_linefeed_unit_tests
    from .tests import semantic_linefeed_manual_tests

    semantic_linefeed_unit_tests.run_unit_tests()
    semantic_linefeed_manual_tests.run_manual_tests()

if __name__ == "__main__":
    run_tests()

Se esegui per la prima volta, questo dovrebbe caricare il modulo, ma se in seguito puoi di nuovo il metodo / funzionerun_tests()ricaricherà i file dei test. Con testo sublime (Python 3.3.6) questo accade spesso perché il suo interprete non si chiude mai (a meno che non si riavvii Sublime Text, cioè ilPython3.3interprete).

fonte