2015-01-23 11 views
6

W Pythonie można przeładować moduł następująco ...pakiety przeładunkowych (i ich Submoduły) rekursywnie w Pythonie

import foobar 

import importlib 
importlib.reload(foobar) 

Działa to dla .py plików, ale dla pakietów Python będzie przeładować tylko pakiet i a nie żadnego z zagnieżdżonych pod-modułów.

Z pakietu:

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

Python Script:

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. 

Nie sugeruje th jest błędem, ale czasami warto ponownie załadować pakiet i wszystkie jego podmoduły. (Jeśli chcesz edytować moduł, gdy skrypt działa na przykład).

Jakie są dobre sposoby rekurencyjnego ponownego załadowania pakietu w Pythonie?

Uwagi:

  • Dla celów tej kwestii przyjąć ostatnią Python3.x

    (obecnie za pomocą importlib)

  • Pozwalając, że może to requre pewne zmiany do samych modułów.
  • Załóżmy, że import symboli wieloznacznych nie jest używany (from foobar import *), ponieważ mogą one komplikować logikę przeładowania.
+2

ipython zapewnia moduł 'IPython.lib.deepreload' dla rekurencyjnego przeładunku. [Kod można znaleźć tutaj] (https://github.com/ipython/ipython/blob/master/IPython/lib/deepreload.py). Co ciekawe, moduł ma 285 sloc. – jme

+0

Świetna wskazówka, ale zastąpienie haków importowych jest rodzajem ciężkiego rozwiązania (które ma sens w przypadku IPython), ale nie fragmentem, którego chciałbym w moim projekcie, aby nieco bardziej użyteczne było ponowne ładowanie. – ideasman42

Odpowiedz

-1

Coś w tym stylu, może?

import importlib 
import types 

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

czy to testowałeś? Dostaję obiekt TypeError: 'module' nie jest iterowalny ", to również będzie się powtarzał nieskończenie, jeśli moduły się do siebie odwołują i na pewno działa w sposób, w jaki działa przestrzeń nazw - to tylko zaktualizuje moduł lokalnie, ale nie moduł podrzędny w pakiecie. – ideasman42

+0

Częściowo to przetestowałem. Co to jest "type (module)", gdy mówi, że nie jest to iterable? Jaki jest łańcuch połączeń, aby się tam dostać? –

+0

To jest moduł '', Wystarczy dodać 'reloadall (types)' na dole przykładu – ideasman42

3

Oto funkcja rekursywnie ładująca pakiet. Sprawdź, czy ponownie załadowane moduły są aktualizowane w modułach, w których są używane, i czy sprawdzane są problemy z nieskończoną rekurencją.

Jeden restrukturyzowanymi to musi działać na pakiet (co ma sens tylko dla pakietów w każdym razie)

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

ta funkcja nie jest całkowicie poprawna, należy wziąć pod uwagę, że istnieją dwa submoduły A i B. obiekty w A zależą od B. Załóżmy, że A jest przeładowywane jako pierwsze, A zaimportuje stare B (ponieważ B nie przeładowało). Rezultatem jest nie do końca zaktualizowana A. –

+0

Dobra rzecz, kiedy zajmie mi trochę czasu, zajrzę do poprawki. – ideasman42