modules from another python python-module python-import

python - from - Versión recursiva de ''recargar''



python import module from path (6)

Cuando estoy desarrollando el código Python, normalmente lo pruebo de forma ad hoc en el intérprete. import some_module , lo import some_module , encontraré un error, lo arreglaré y lo guardaré, y luego reload(some_module) función de reload incorporada para reload(some_module) y probar de nuevo.

Sin embargo, supongamos que en some_module he import some_other_module , y mientras some_module , descubro un error en some_other_module y lo soluciono. Ahora, llamar a reload(some_module) no volverá a importar recursivamente some_other_module . Tengo que reimportar manualmente la dependencia (haciendo algo como reload(some_module.some_other_module) , o import some_other_module; reload(some_other_module) , o, si he cambiado un montón de dependencias y he perdido la pista de lo que necesito volver a cargar , Necesito reiniciar todo el intérprete.

Lo que sería más conveniente es si existiera alguna función recursive_reload , y podría hacer recursive_reload(some_module) y hacer que Python no solo recargue some_module , sino que también recursivamente recargue todos los módulos que some_module importa (y cada módulo que importan) , y así sucesivamente) para poder estar seguro de que no estaba usando una versión antigua de ninguno de los otros módulos de los que depende some_module .

No creo que haya algo incorporado en Python que se comporte como la función recursive_reload que describo aquí, pero ¿hay una manera fácil de hackear algo así juntos?


¿No sería más sencillo escribir algunos casos de prueba y ejecutarlos cada vez que termine de modificar su módulo?

Lo que estás haciendo es genial (en esencia estás usando TDD (desarrollo guiado por pruebas) pero lo estás haciendo mal.

Tenga en cuenta que con las pruebas unitarias escritas (utilizando el módulo de prueba de unidad de Python predeterminado, o mejor aún, la nose ) puede tener pruebas que sean reutilizables , estables y que le ayuden a detectar las inconsitencias en su código mucho más rápido y mejor que con la prueba de su módulo en el interactivo. ambiente.



He encontrado la respuesta de redsk muy útil. Propongo una versión simplificada (para el usuario, no como código) donde la ruta al módulo se recopila automáticamente y la recursión funciona para un número arbitrario de niveles. Todo es autocontenido en una sola función. Probado en Python 3.4. Supongo que para Python 3.3 uno debe import reload from imp lugar de ... from importlib . También verifica si el archivo __file__ está presente, lo que podría ser falso si el codificador se olvida de definir un archivo __init__.py en un submódulo. En tal caso, se plantea una excepción.

def rreload(module): """ Recursive reload of the specified module and (recursively) the used ones. Mandatory! Every submodule must have an __init__.py file Usage: import mymodule rreload(mymodule) :param module: the module to load (the module itself, not a string) :return: nothing """ import os.path import sys def rreload_deep_scan(module, rootpath, mdict=None): from types import ModuleType from importlib import reload if mdict is None: mdict = {} if module not in mdict: # modules reloaded from this module mdict[module] = [] # print("RReloading " + str(module)) reload(module) for attribute_name in dir(module): attribute = getattr(module, attribute_name) # print ("for attr "+attribute_name) if type(attribute) is ModuleType: # print ("typeok") if attribute not in mdict[module]: # print ("not int mdict") if attribute.__name__ not in sys.builtin_module_names: # print ("not a builtin") # If the submodule is a python file, it will have a __file__ attribute if not hasattr(attribute, ''__file__''): raise BaseException("Could not find attribute __file__ for module ''"+str(attribute)+"''. Maybe a missing __init__.py file?") attribute_path = os.path.dirname(attribute.__file__) if attribute_path.startswith(rootpath): # print ("in path") mdict[module].append(attribute) rreload_deep_scan(attribute, rootpath, mdict) rreload_deep_scan(module, rootpath=os.path.dirname(module.__file__))


Me he topado con el mismo problema y he creado las respuestas de @Mattew y @osa.

from types import ModuleType import os, sys def rreload(module, paths=None, mdict=None): """Recursively reload modules.""" if paths is None: paths = [''''] if mdict is None: mdict = {} if module not in mdict: # modules reloaded from this module mdict[module] = [] reload(module) for attribute_name in dir(module): attribute = getattr(module, attribute_name) if type(attribute) is ModuleType: if attribute not in mdict[module]: if attribute.__name__ not in sys.builtin_module_names: if os.path.dirname(attribute.__file__) in paths: mdict[module].append(attribute) rreload(attribute, paths, mdict) reload(module) #return mdict

Hay tres diferencias:

  1. En el caso general, se debe llamar a recargar (módulo) al final de la función también, como se señaló @osa.
  2. Con las dependencias de importación circular, el código publicado anteriormente se repetirá para siempre, así que he agregado un diccionario de listas para realizar un seguimiento del conjunto de módulos cargados por otros módulos. Si bien las dependencias circulares no son geniales, Python las permite, por lo que esta función de recarga también las trata.
  3. He agregado una lista de rutas (la predeterminada es ['''']) desde la cual se permite la recarga. A algunos módulos no les gusta haber sido recargados de la forma normal, (como se muestra here ).

Me he topado con el mismo problema y me inspiraste para resolver el problema.

from types import ModuleType def rreload(module): """Recursively reload modules.""" reload(module) for attribute_name in dir(module): attribute = getattr(module, attribute_name) if type(attribute) is ModuleType: rreload(attribute)

O, si está usando IPython, simplemente use dreload o pass --deep-reload en el inicio.


Técnicamente, en cada archivo puede poner un comando de recarga, para asegurarse de que se recarga cada vez que se importa.

a.py:

def testa(): print ''hi!''

b.py:

import a reload(a) def testb(): a.testa()

Ahora, interactivamente:

import b b.testb() #hi! #<modify a.py> reload(b) b.testb() #hello again!