Rechargement des sous-modules dans IPython

363

Actuellement, je travaille sur un projet python qui contient des sous-modules et utilise numpy / scipy. Ipython est utilisé comme console interactive. Malheureusement, je ne suis pas très satisfait du flux de travail que j'utilise actuellement, j'apprécierais quelques conseils.

Dans IPython, le framework est chargé par une simple importcommande. Cependant, il est souvent nécessaire de changer de code dans l'un des sous-modules du framework. À ce stade, un modèle est déjà chargé et j'utilise IPython pour interagir avec lui.

Maintenant, le framework contient de nombreux modules qui dépendent les uns des autres, c'est-à-dire que lorsque le framework est initialement chargé, le module principal importe et configure les sous-modules. Les modifications du code ne sont exécutées que si le module est rechargé à l'aide de reload(main_mod.sub_mod). C'est lourd car j'ai besoin de recharger tous les modules modifiés individuellement en utilisant le chemin complet. Il serait très pratique de reload(main_module)recharger également tous les sous-modules, mais sans recharger numpy / scipy ..

Alain
la source
Souhaitez-vous développer davantage However, it is often necessary to change code in one of the submodules of the framework.Alors pourquoi necessary to change code? Merci
manger
16
@eat: Le framework est continuellement développé, il y a donc des changements constants dans la base de code.
Alain

Réponses:

531

IPython est livré avec une magie de rechargement automatique :

%load_ext autoreload
%autoreload 2

Il rechargera tous les modules modifiés à chaque fois avant d'exécuter une nouvelle ligne. La façon dont cela fonctionne est légèrement différente de dreload. Certaines mises en garde s'appliquent, tapez %autoreload?pour voir ce qui peut mal se passer.


Si vous souhaitez toujours activer ces paramètres, modifiez votre fichier de configuration IPython ~/.ipython/profile_default/ipython_config.py[1] et ajoutez:

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

Merci à @Kos via un commentaire ci-dessous.

[1] Si vous n'avez pas le fichier ~/.ipython/profile_default/ipython_config.py, vous devez d' ipython profile createabord appeler . Ou le fichier peut être localisé à $IPYTHONDIR.

pv.
la source
63
J'ai c.InteractiveShellApp.extensions = ['autoreload']et c.InteractiveShellApp.exec_lines = ['%autoreload 2']dans mon ~/.ipython/profile_default/ipython_config.py.
Kos
4
Cependant, cela pourrait être un impact sur les performances, alors utilisez-le avec prudence.
asmeurer
3
Le rechargement n'est effectué que lorsque vous appuyez sur Entrée dans le shell Ipython, et n'est généralement pas perceptible.
pv.
3
Cela fonctionne très bien lors du débogage de packages, donc quel est le but de dreload, il semble que dreload soit trop invasif et affiche une erreur lorsque certains packages comme matplotlib sont chargés.
dashesy
3
Si vous utilisez la méthode @Kos, assurez-vous que c est défini: c = get_config ()
Tickon
27

Dans IPython 0.12 (et peut-être plus tôt), vous pouvez utiliser ceci:

%load_ext autoreload
%autoreload 2

C'est essentiellement la même chose que la réponse de pv. , sauf que l'extension a été renommée et est maintenant chargée à l'aide de %load_ext.

RafG
la source
20

Pour une raison quelconque, ni %autoreload, ni ne dreloadsemble fonctionner pour la situation lorsque vous importez du code d'un ordinateur portable à un autre . Seul Python reloadfonctionne:

reload(module)

Basé sur [1] .

Dennis Golomazov
la source
10
Dans Python 3.4+, vous pouvez trouver un rechargement dans le module importlib. Voir cette question .
Praveen
1
Cette méthode fonctionne lors de l'ajout d'une méthode d'instance, contrairement à la %autoreloadtechnique. Il y a un rapport de bogue ouvert pour ajouter un support à %autoreloadcela. .
ijoseph
18

IPython propose dreload()de recharger récursivement tous les sous-modules. Personnellement, je préfère utiliser la %run()commande magique (bien qu'elle n'effectue pas de rechargement profond, comme l'a souligné John Salvatier dans les commentaires).

Sven Marnach
la source
11
Je pense que (malheureusement)% run script.py ne recharge que le script que vous appelez, pas les packages qu'il importe. Si vous essayez de déboguer un package que vous créez, cela peut être pénible.
John Salvatier
2
NB. dreloada été remplacé dans IPython récent (par exemple IPython 6.0) par deepreload .
dan mackinlay
8

Le module nommé importlibpermet d'accéder aux importations internes. Surtout, il fournit une fonction importlib.reload():

import importlib
importlib.reload(my_module)

Au contraire de %autoreload, importlib.reload()réinitialisez également les variables globales définies dans le module. Dans la plupart des cas, c'est ce que vous voulez.

importlibn'est disponible que depuis Python 3.1. Pour une version plus ancienne, vous devez utiliser le module imp.

Jérôme Pouiller
la source
seule solution qui a fonctionné pour moi
gustavz
5

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

Pour éviter de taper ces fonctions magiques encore et encore, elles pourraient être placées dans le script de démarrage ipython (nommez-le avec le suffixe .py sous .ipython / profile_default / startup. Tous les scripts python sous ce dossier seront chargés selon l'ordre lexical), qui ressemble à ceci:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")
Pégase
la source
Cela semble également fonctionner si vous exécutez votre script avec, par exemple, %run script.pyde l'IPython REPL
Patrick Sanan
3

Que dis-tu de ça:

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

Cela devrait recharger efficacement l'arborescence complète des modules et sous-modules que vous lui donnez. Vous pouvez également mettre cette fonction dans votre .ipythonrc (je pense) afin qu'elle soit chargée à chaque démarrage de l'interpréteur.

YH Wong
la source
Cela semble bien, cependant, il se peut qu'il ne couvre pas les modules ou les membres de modules importés à l'aide de from ... import ...ou import ... as. Au moins, cela me pose souvent des problèmes lorsque je travaille de manière interactive sur le terminal. Je suis passé à l'utilisation de macros stockées dans IPython qui effectuent les importations et les configurations nécessaires pour commencer à travailler dans un état prédéfini.
Bernhard
Il couvre en fait from ... import ...et import ... astant que la chose que vous avez importée est un module. La seule chose qu'il ne couvre pas, ce sont les modules d'un package qui n'ont pas été chargés à partir de son __init__.pyfichier. Pour les packages, vous pouvez probablement vérifier si l' __path__attribut du module est un répertoire. Si c'est le cas, parcourez-le et importez récursivement tous les modules que vous pourriez trouver. Je n'ai pas écrit cette partie car l'auteur n'a pas demandé de solution pour les packages.
YH Wong
En effet, cela semble bon. J'ai pensé à cette possibilité, en même temps, je m'attendrais à ce qu'il y ait des fonctionnalités intégrées, c'est-à-dire basées sur cela . Cependant, il n'était pas clair pour moi comment l'utiliser. Après quelques recherches qui auraient dû avoir lieu avant de poster la question d'origine, j'ai trouvé cette extension .
Alain
Vous pouvez également utiliser pkgutilpour obtenir tous les sous-modules dans un package, même si le package n'importe pas les sous-modules dans le module supérieur. stackoverflow.com/a/1707786/1243926
osa
vous devez également faire: pour le module danssys.modules:
aoeu256
2

Une autre option:

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

Vérifié sur ipython et ipython3 v5.1.0 sur Ubuntu 14.04.

Tchad
la source
1

Ma pratique standard pour le rechargement est de combiner les deux méthodes après la première ouverture de IPython:

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

Le chargement des modules avant de le faire empêchera leur rechargement, même avec un manuel reload(module_name). J'ai toujours, très rarement, des problèmes inexplicables avec les méthodes de classe ne rechargeant pas que je n'ai pas encore examinées.

ryanjdillon
la source
1

Notez que ce qui précède autoreloadne fonctionne dans IntelliJ que si vous enregistrez manuellement le fichier modifié (par exemple en utilisant ctrl + s ou cmd + s). Cela ne semble pas fonctionner avec la sauvegarde automatique.

Hubert Grzeskowiak
la source
Je confirme que c'est également le cas pour PyCharm.
tsando
0

Sur les ordinateurs portables Jupyter sur Anaconda, procédez comme suit:

%load_ext autoreload
%autoreload 2

produit le message:

L'extension de chargement automatique est déjà chargée. Pour le recharger, utilisez: %reload_ext autoreload

Il semble préférable de faire:

%reload_ext autoreload
%autoreload 2

Information sur la version:

La version du serveur Notebook est 5.0.0 et fonctionne sur: Python 3.6.2 | Anaconda, Inc. | (par défaut, 20 septembre 2017, 13:35:58) [MSC v.1900 32 bits (Intel)]

Merci d'avance
la source
0

Tous les sous-objets ne seront pas rechargés par cela, je crois que vous devez utiliser la charge avancée de IPython pour cela.

aoeu256
la source