Recarregando submódulos no IPython

363

Atualmente, estou trabalhando em um projeto python que contém submódulos e usa numpy / scipy. O Ipython é usado como console interativo. Infelizmente, não estou muito satisfeito com o fluxo de trabalho que estou usando agora, gostaria de receber alguns conselhos.

No IPython, a estrutura é carregada por um importcomando simples . No entanto, geralmente é necessário alterar o código em um dos submódulos da estrutura. Neste ponto, um modelo já está carregado e eu uso o IPython para interagir com ele.

Agora, a estrutura contém muitos módulos que dependem uma da outra, ou seja, quando a estrutura é carregada inicialmente, o módulo principal está importando e configurando os submódulos. As alterações no código são executadas apenas se o módulo for recarregado usando reload(main_mod.sub_mod). Isso é complicado, pois preciso recarregar todos os módulos alterados individualmente, usando o caminho completo. Seria muito conveniente se reload(main_module)também recarregasse todos os submódulos, mas sem recarregar numpy / scipy ..

Alain
fonte
Você gostaria de elaborar mais sobre However, it is often necessary to change code in one of the submodules of the framework.Então, por que é necessary to change code? Obrigado
comer
16
@eat: O framework está sendo desenvolvido continuamente, portanto há mudanças constantes na base de código.
Alain

Respostas:

531

O IPython vem com alguma mágica de recarga automática :

%load_ext autoreload
%autoreload 2

Ele recarregará todos os módulos alterados todas as vezes antes de executar uma nova linha. A maneira como isso funciona é um pouco diferente dreload. Algumas advertências se aplicam, digite %autoreload?para ver o que pode dar errado.


Se você deseja sempre ativar essas configurações, modifique seu arquivo de configuração IPython ~/.ipython/profile_default/ipython_config.py[1] e adicione:

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

Crédito para @Kos através de um comentário abaixo.

[1] Se você não possui o arquivo ~/.ipython/profile_default/ipython_config.py, precisa ligar ipython profile createprimeiro. Ou o arquivo pode estar localizado em $IPYTHONDIR.

pv.
fonte
63
Eu tenho c.InteractiveShellApp.extensions = ['autoreload']e c.InteractiveShellApp.exec_lines = ['%autoreload 2']no meu ~/.ipython/profile_default/ipython_config.py.
Kos
4
Porém, isso pode afetar o desempenho, portanto, use com cuidado.
asmeurer
3
A recarga é realizada apenas quando você pressiona Enter no shell Ipython, e geralmente não é perceptível.
pv.
3
Isso funciona muito bem ao depurar pacotes, então qual é o objetivo do dreload, parece que o dreload é muito invasivo e imprime erro quando alguns pacotes como o matplotlib são carregados.
131313 dashesy
3
Se você usar o método @Kos, certifique-se c é definido: c = get_config ()
Tickon
27

No IPython 0.12 (e possivelmente anterior), você pode usar isto:

%load_ext autoreload
%autoreload 2

Isto é essencialmente o mesmo que a resposta por pv. , exceto que a extensão foi renomeada e agora é carregada usando %load_ext.

RafG
fonte
20

Por algum motivo, %autoreloadnem dreloadparece funcionar para a situação quando você importa código de um notebook para outro . Somente o Python simples reloadfunciona:

reload(module)

Baseado em [1] .

Dennis Golomazov
fonte
10
No Python 3.4+, você pode encontrar recarga no módulo importlib. Veja esta pergunta .
precisa
11
Este método funciona ao adicionar um método de instância, diferentemente da %autoreloadtécnica. Há um relatório de bug aberto para adicionar suporte %autoreloadpara isso. .
ijoseph
18

O IPython oferece dreload()recarregar recursivamente todos os submódulos. Pessoalmente, prefiro usar o %run()comando mágico (embora ele não execute uma recarga profunda, como apontado por John Salvatier nos comentários).

Sven Marnach
fonte
11
Eu acho que (infelizmente)% run script.py apenas recarrega o script que você está chamando, não os pacotes que ele importa. Se você está tentando depurar um pacote que está construindo, isso pode ser um problema.
precisa
2
NB dreloadfoi substituído no IPython recente (por exemplo, IPython 6.0) por deepreload .
precisa saber é o seguinte
8

Módulo denominado importlibpermitir acessar para importar internals. Especialmente, fornece a função importlib.reload():

import importlib
importlib.reload(my_module)

Ao contrário %autoreload, importlib.reload()também redefina as variáveis ​​globais definidas no módulo. Na maioria dos casos, é o que você deseja.

importlibestá disponível apenas desde o Python 3.1. Para a versão mais antiga, você tem que usar o módulo imp.

Jérôme Pouiller
fonte
única solução que funcionou para mim
gustavz 16/04
5

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

Para evitar digitar essas funções mágicas repetidamente, elas podem ser colocadas no script de inicialização do ipython (nomeie-o com o sufixo .py em .ipython / profile_default / startup. Todos os scripts python nessa pasta serão carregados de acordo com a ordem lexical), que se parece com o seguinte:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")
Pegasus
fonte
Isso também parece funcionar se você estiver executando o seu roteiro com, por exemplo %run script.pya partir do IPython REPL
Patrick Sanan
3

Que tal agora:

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())

Isso deve recarregar efetivamente toda a árvore de módulos e submódulos fornecidos. Você também pode colocar essa função no seu .ipythonrc (eu acho) para que ela seja carregada toda vez que você iniciar o intérprete.

YH Wong
fonte
Parece bom, no entanto, pode ser que ele não esteja cobrindo módulos ou membros de módulos importados usando from ... import ...or import ... as. Pelo menos isso está me causando problemas ao trabalhar interativamente no terminal. Eu mudei para usar macros armazenadas no IPython que fazem as importações e configurações necessárias para começar a trabalhar em um estado predefinido.
21111 Bernhard
Na verdade, abrange from ... import ...e import ... asdesde que o que você importou seja um módulo. A única coisa que ele não cobre são os módulos de um pacote que não foram carregados do __init__.pyarquivo. Para pacotes, você provavelmente pode verificar se o __path__atributo do módulo é um diretório. Se estiver, percorra-o e importe recursivamente todos os módulos que você pôde encontrar. Não escrevi esta parte porque o autor não pediu uma solução para os pacotes.
YH Wong
Na verdade, isso parece bom. Pensei nessa possibilidade, ao mesmo tempo esperaria que houvesse alguma funcionalidade incorporada, ou seja, com base nisso . No entanto, não estava claro para mim como usar isso. Após algumas escavações que deveriam ter ocorrido antes de eu postar a pergunta original, encontrei esta extensão .
Alain
Além disso, você pode usar pkgutilpara obter todos os submódulos de um pacote, mesmo que o pacote não importe os submódulos para o módulo superior. stackoverflow.com/a/1707786/1243926
osa
você também tem que fazer: for module insys.modules:
aoeu256
2

Outra opção:

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

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

Chade
fonte
1

Minha prática padrão para recarregar é combinar os dois métodos após a primeira abertura de IPython:

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

Carregar módulos antes de fazer isso fará com que eles não sejam recarregados, mesmo com um manual reload(module_name). Eu ainda, muito raramente, tenho problemas inexplicáveis ​​com métodos de classe que não são recarregados que ainda não examinei.

ryanjdillon
fonte
1

Observe que o mencionado acima autoreloadsó funciona no IntelliJ se você salvar manualmente o arquivo alterado (por exemplo, usando ctrl + s ou cmd + s). Parece não funcionar com o salvamento automático.

Hubert Grzeskowiak
fonte
Confirmo que esse também é o caso do PyCharm.
tsando 12/02
0

Nos cadernos Jupyter no Anaconda, faça o seguinte:

%load_ext autoreload
%autoreload 2

produziu a mensagem:

A extensão de carregamento automático já está carregada. Para recarregá-lo, use: %reload_ext autoreload

Parece que é preferível fazer:

%reload_ext autoreload
%autoreload 2

Versão informação:

A versão do servidor de notebook é 5.0.0 e está em execução no: Python 3.6.2 | Anaconda, Inc. | (padrão, 20 de setembro de 2017, 13:35:58) [MSC v.1900 32 bits (Intel)]

desde já, obrigado
fonte
0

Quaisquer subobjetos não serão recarregados por isso, acredito que você precise usar o deepreload do IPython para isso.

aoeu256
fonte