Recargar submódulos en IPython


363

Actualmente estoy trabajando en un proyecto de Python que contiene submódulos y usa numpy / scipy. Ipython se usa como consola interactiva. Desafortunadamente no estoy muy contento con el flujo de trabajo que estoy usando en este momento, agradecería algunos consejos.

En IPython, el marco se carga mediante un importcomando simple . Sin embargo, a menudo es necesario cambiar el código en uno de los submódulos del marco. En este punto, un modelo ya está cargado y uso IPython para interactuar con él.

Ahora, el marco contiene muchos módulos que dependen unos de otros, es decir, cuando el marco se carga inicialmente, el módulo principal está importando y configurando los submódulos. Los cambios en el código solo se ejecutan si el módulo se vuelve a cargar usando reload(main_mod.sub_mod). Esto es engorroso ya que necesito volver a cargar todos los módulos modificados individualmente usando la ruta completa. Sería muy conveniente reload(main_module)recargar todos los submódulos, pero sin recargar numpy / scipy.


¿Te gustaría elaborar más sobre However, it is often necessary to change code in one of the submodules of the framework.Entonces, por qué necessary to change code? Gracias
comer

16
@eat: el marco se está desarrollando continuamente, por lo que hay cambios constantes en la base del código.
Alain

Respuestas:


531

IPython viene con algo de magia de recarga automática :

%load_ext autoreload
%autoreload 2

Recargará todos los módulos modificados cada vez antes de ejecutar una nueva línea. La forma en que esto funciona es ligeramente diferente de dreload. Se aplican algunas advertencias, escriba %autoreload?para ver qué puede salir mal.


Si desea habilitar siempre esta configuración, modifique su archivo de configuración de IPython ~/.ipython/profile_default/ipython_config.py[1] y agregue:

c.InteractiveShellApp.extensions = ['autoreload']     
c.InteractiveShellApp.exec_lines = ['%autoreload 2']

Crédito a @Kos a través de un comentario a continuación.

[1] Si no tiene el archivo ~/.ipython/profile_default/ipython_config.py, ipython profile createprimero debe llamar . O el archivo puede estar ubicado en $IPYTHONDIR.


63
Tengo c.InteractiveShellApp.extensions = ['autoreload']y c.InteractiveShellApp.exec_lines = ['%autoreload 2']en mi ~/.ipython/profile_default/ipython_config.py.
Kos

44
Sin embargo, eso podría ser un éxito en el rendimiento, así que úselo con precaución.
Asmeurer

3
La recarga solo se realiza cuando presionas Enter en el shell de Ipython, y generalmente no se nota.
pv.

3
Esto funciona bastante bien al depurar paquetes, por lo que cuál es el propósito de dreload, parece que dreload es demasiado invasivo e imprime un error cuando se cargan algunos paquetes como matplotlib.
dashesy

3
Si usa el método @Kos, asegúrese de que c esté definido: c = get_config ()
Tickon

27

En IPython 0.12 (y posiblemente antes), puede usar esto:

%load_ext autoreload
%autoreload 2

Esto es esencialmente lo mismo que la respuesta de pv. , excepto que la extensión ha cambiado de nombre y ahora se carga con %load_ext.


20

Por alguna razón, %autoreloadni dreloadparece funcionar para la situación cuando importa código de una computadora portátil a otra . Solo Python simple reloadfunciona:

reload(module)

Basado en [1] .


10
En Python 3.4+, puede encontrar la recarga en el módulo importlib. Ver esta pregunta .
Praveen

1
Este método funciona al agregar un método de instancia, a diferencia de la %autoreloadtécnica. Hay un informe de error abierto para agregar soporte %autoreloadpara esto. .
ijoseph

18

IPython ofrece dreload()recargar recursivamente todos los submódulos. Personalmente, prefiero usar el %run()comando mágico (aunque no realiza una recarga profunda, como lo señala John Salvatier en los comentarios).


11
Creo que (desafortunadamente)% run script.py solo vuelve a cargar el script que está llamando, no los paquetes que importa. Si está intentando depurar un paquete que está creando, esto puede ser una molestia.
John Salvatier

2
NÓTESE BIEN. dreloadha sido reemplazado en IPython reciente (por ejemplo, IPython 6.0) por deepreload .
dan mackinlay

8

El módulo llamado importlibpermite acceder a las partes internas de importación. Especialmente, proporciona función importlib.reload():

import importlib
importlib.reload(my_module)

Por el contrario %autoreload, importlib.reload()también restablece las variables globales establecidas en el módulo. En la mayoría de los casos, es lo que quieres.

importlibsolo está disponible desde Python 3.1. Para la versión anterior, debe usar el módulo imp.


única solución que funcionó para mí
gustavz

5

http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/

Para evitar escribir esas funciones mágicas una y otra vez, podrían colocarse en el script de inicio de ipython (nómbrelo con el sufijo .py bajo .ipython / profile_default / startup. Todos los scripts de python en esa carpeta se cargarán de acuerdo con el orden léxico), que se parece a lo siguiente:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")

Esto también parece funcionar si está ejecutando su script con, por ejemplo, %run script.pydesde IPython REPL
Patrick Sanan

3

Qué tal esto:

import inspect

# needs to be primed with an empty set for loaded
def recursively_reload_all_submodules(module, loaded=None):
    for name in dir(module):
        member = getattr(module, name)
        if inspect.ismodule(member) and member not in loaded:
            recursively_reload_all_submodules(member, loaded)
    loaded.add(module)
    reload(module)

import mymodule
recursively_reload_all_submodules(mymodule, set())

Esto debería recargar de manera efectiva todo el árbol de módulos y submódulos que le dé. También puede poner esta función en su .ipythonrc (creo) para que se cargue cada vez que inicie el intérprete.


Eso se ve bien, sin embargo, podría ser que no está cubriendo módulos o miembros de módulos que se importan usando from ... import ...o import ... as. Al menos eso me da problemas a menudo cuando trabajo de forma interactiva en la terminal. Pasé a usar macros almacenadas en IPython que hacen las importaciones y configuraciones necesarias para comenzar a trabajar en un estado predefinido.
Bernhard

En realidad cubre from ... import ...y import ... assiempre que lo que haya importado sea un módulo. Lo único que no cubre son los módulos en un paquete que no se cargaron desde su __init__.pyarchivo. Para los paquetes, probablemente pueda verificar si el __path__atributo del módulo es un directorio. Si es así, recorra e importe recursivamente todos los módulos que pueda encontrar. No escribí esta parte porque el autor no ha pedido una solución para los paquetes.
YH Wong

De hecho, esto se ve bien. Pensé en esta posibilidad, al mismo tiempo esperaría que hubiera alguna funcionalidad integrada, es decir, basada en esto . Sin embargo, no estaba claro para mí cómo usar esto. Después de algo de excavación que debería haber ocurrido antes de publicar la pregunta original, encontré esta extensión .
Alain

También puede usar pkgutilpara obtener todos los submódulos en un paquete, incluso si el paquete no importa los submódulos en el módulo superior. stackoverflow.com/a/1707786/1243926
osa

también tiene que hacer: para el módulo ensys.modules:
aoeu256

2

Otra opción:

$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF

Verificado en ipython e ipython3 v5.1.0 en Ubuntu 14.04.


1

Mi práctica estándar para la recarga es combinar ambos métodos después de la primera apertura de IPython:

from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2

Cargar módulos antes de hacer esto hará que no se vuelvan a cargar, incluso con un manual reload(module_name). Todavía, muy raramente, tengo problemas inexplicables con los métodos de clase que no se vuelven a cargar y que aún no he investigado.


1

Tenga en cuenta que lo mencionado anteriormente autoreloadsolo funciona en IntelliJ si guarda manualmente el archivo modificado (por ejemplo, usando ctrl + so cmd + s). No parece funcionar con el guardado automático.


Confirmo que este es el caso también para PyCharm.
tsando

0

En Jupyter Notebooks en Anaconda, haciendo esto:

%load_ext autoreload
%autoreload 2

produjo el mensaje:

La extensión de autocarga ya está cargada. Para recargarlo, use: %reload_ext autoreload

Parece que es preferible hacer:

%reload_ext autoreload
%autoreload 2

Información de versión:

La versión del servidor portátil es 5.0.0 y se ejecuta en: Python 3.6.2 | Anaconda, Inc. | (predeterminado, 20 de septiembre de 2017, 13:35:58) [MSC v.1900 32 bit (Intel)]


0

Esto no recargará ningún subobjeto, creo que debe usar la recarga profunda de IPython para eso.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.