2015-01-23 22 views
6

In Python è possibile ricaricare un modulo come segue ...pacchetti di ricarica (e le loro sottomoduli) ricorsivamente in Python

import foobar 

import importlib 
importlib.reload(foobar) 

Questo funziona per .py file, ma per pacchetti di Python si ricaricherà solo il pacchetto e non uno qualsiasi dei sottomoduli nidificati.

Con un pacchetto:

  • foobar/__init__.py
  • foobar/spam.py
  • foobar/eggs.py

Script Python:

import foobar 

# assume `spam/__init__.py` is importing `.spam` 
# so we dont need an explicit import. 
print(foobar.spam) # ok 

import importlib 
importlib.reload(foobar) 
# foobar.spam WONT be reloaded. 

Non suggerire ° è un bug, ma a volte è utile ricaricare un pacchetto e tutti i suoi sottomoduli. (Se si desidera modificare un modulo mentre uno script viene eseguito ad esempio).

Quali sono alcuni buoni modi per ricaricare ricorsivamente un pacchetto in Python?

Note:

  • Ai fini di questa domanda assumono l'ultima Python3.x

    (attualmente in uso importlib)

  • Permettere che questo può requre alcune modifiche ai moduli stessi.
  • Supporre che le importazioni con caratteri jolly non vengano utilizzate (from foobar import *), poiché potrebbero complicare la logica di ricarica.
+2

IPython fornisce il modulo 'IPython.lib.deepreload' di ricarica ricorsivo. Il [codice può essere trovato qui] (https://github.com/ipython/ipython/blob/master/IPython/lib/deepreload.py). È interessante notare che il modulo è 285 sloc. – jme

+0

Un grande suggerimento, ma la sostituzione dei ganci di importazione è una sorta di soluzione pesante (che ha senso per IPython) ma non alcuni frammenti che vorrei nel mio progetto solo per ricaricarmi lavorando un po 'più utilmente. – ideasman42

risposta

-1

Qualcosa di simile, forse?

import importlib 
import types 

def reloadall(module): 
    importlib.reload(module) 
    for child in module: 
     if isinstance(child, types.ModuleType): 
      reloadall(child) 
+0

hai provato questo? Ottengo 'TypeError: 'module' object is not iterable ', Inoltre questo ricoderà all'infinito se i moduli si fanno riferimento a vicenda, e sicuramente il modo in cui funziona lo spazio dei nomi - questo aggiornerà solo il modulo localmente, ma non il sottomodulo all'interno del pacchetto. – ideasman42

+0

L'ho parzialmente testato. Cos'è 'type (module)' quando ti dice che non è iterable? Qual è la catena di chiamate per arrivarci? –

+0

È un '', Basta aggiungere 'reloadall (types)' nella parte inferiore dell'esempio – ideasman42

3

Ecco una funzione che carica in modo ricorsivo un pacchetto. Controlla che i moduli ricaricati siano aggiornati nei moduli in cui vengono utilizzati e che vengano verificati i problemi con ricorsione infinita.

Uno di restauro è necessario eseguire su un pacchetto (che senso solo per i pacchetti comunque)

import os 
import types 
import importlib 


def reload_package(package): 
    assert(hasattr(package, "__package__")) 
    fn = package.__file__ 
    fn_dir = os.path.dirname(fn) + os.sep 
    module_visit = {fn} 
    del fn 

    def reload_recursive_ex(module): 
     importlib.reload(module) 

     for module_child in vars(module).values(): 
      if isinstance(module_child, types.ModuleType): 
       fn_child = getattr(module_child, "__file__", None) 
       if (fn_child is not None) and fn_child.startswith(fn_dir): 
        if fn_child not in module_visit: 
         # print("reloading:", fn_child, "from", module) 
         module_visit.add(fn_child) 
         reload_recursive_ex(module_child) 

    return reload_recursive_ex(package) 

# example use 
import os 
reload_package(os) 
+1

questa funzione non è del tutto corretta, si consideri che ci sono due sottomoduli A e B. gli oggetti in A dipendono da B. Supponiamo che A venga ricaricato per primo, A importerebbe il vecchio B (poiché B non ha ricaricato). Ne risulta un A. non completamente aggiornato –

+0

Un buon punto, cercherò una correzione quando avrò un po 'di tempo. – ideasman42

Problemi correlati