web-dev-qa-db-fra.com

Comment décharger (recharger) un module Python?

J'ai un serveur Python de longue durée et j'aimerais pouvoir mettre à niveau un service sans redémarrer le serveur. Quelle est la meilleure façon de faire ça?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
679
Mark Harrison

Vous pouvez recharger un module alors qu'il a déjà été importé à l'aide de la fonction intégrée reload :

from importlib import reload  # Python 3.4+ only.
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

Dans Python 3, reload a été déplacé vers le module imp . En 3.4, imp a été déconseillé au profit de importlib , et reload a été ajouté à ce dernier. Lorsque vous ciblez 3 ou plus, référencez le module approprié lorsque vous appelez reload ou importez-le.

Je pense que c'est ce que tu veux. Les serveurs Web tels que le serveur de développement de Django l'utilisent pour que vous puissiez voir les effets de vos modifications de code sans redémarrer le processus du serveur lui-même.

Pour citer les docs:

Le code des modules Python est recompilé et le code de niveau module ré-exécuté, définir un nouvel ensemble d'objets qui sont liés à des noms dans le module dictionnaire. La fonction init de Les modules d'extension ne s'appellent pas un deuxième fois. Comme avec tous les autres objets en Python, les anciens objets ne sont que récupérées après leur décompte de références descendre à zéro. Les noms dans le module Les espaces de noms sont mis à jour pour pointer vers n'importe quel objets nouveaux ou modifiés. Autre les références aux anciens objets (tels que noms externes au module) ne sont pas rebond pour faire référence aux nouveaux objets et doit être mis à jour dans chaque espace de noms où ils se produisent si cela est souhaité.

Comme vous l'avez indiqué dans votre question, vous devrez reconstruire les objets Foo si la classe Foo réside dans le module foo.

634
cdleary

Dans Python 3.0–3.3, vous utiliseriez: imp.reload(module)

Le BDFL a a répondu à cette question.

Cependant, imp A &EACUTE;T&EACUTE; D&EACUTE;CONSEILL&EACUTE; DANS LA VERSION 3.4 AU PROFIT DE importlib (merci @Stefan! ).

Je je pense, donc vous utiliseriez maintenant importlib.reload(module) , bien que je ne sois pas sûr.

241
Paul D. Waite

Il peut être particulièrement difficile de supprimer un module si ce n'est pas du pur Python.

Voici quelques informations sur: Comment puis-je vraiment supprimer un module importé?

Vous pouvez utiliser sys.getrefcount () pour connaître le nombre réel de références.

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

Les nombres supérieurs à 3 indiquent que il sera difficile de se débarrasser du module. La maison "vide" (ne contenant rien) module devrait être ordures collectées après

>>> del sys.modules["empty"]
>>> del empty

en tant que troisième référence est un artefact de la fonction getrefcount ().

81
Gregg Lind

reload(module), mais seulement si c'est complètement autonome. Si quelque chose d'autre a une référence au module (ou à un objet appartenant au module), alors vous obtiendrez des erreurs subtiles et curieuses causées par l'ancien code qui traîne plus longtemps que prévu, et des choses comme isinstance ne fonctionnant pas avec différentes versions de le même code.

Si vous avez des dépendances à sens unique, vous devez également recharger tous les modules qui dépendent du module rechargé pour supprimer toutes les références à l'ancien code. Et puis rechargez les modules qui dépendent des modules rechargés, de manière récursive.

Si vous avez des dépendances circulaires, ce qui est très courant par exemple pour le rechargement d'un paquet, vous devez décharger tous les modules du groupe en une fois. Vous ne pouvez pas faire cela avec reload() car il réimportera chaque module avant que ses dépendances aient été actualisées, permettant ainsi aux anciennes références de s’insérer dans de nouveaux modules.

Dans ce cas, la seule façon de le faire est de pirater sys.modules, ce qui est un peu non supporté. Vous devez supprimer et supprimer chaque entrée sys.modules que vous souhaitez recharger lors de la prochaine importation, ainsi que les entrées dont la valeur est None pour résoudre un problème d'implémentation lié à la mise en cache des importations relatives échouées. Ce n'est pas très gentil, mais tant que vous avez un ensemble de dépendances entièrement autonome qui ne laisse pas de références en dehors de sa base de code, c'est réalisable.

Il est probablement préférable de redémarrer le serveur. :-)

62
bobince
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
57
Kumaresan

Pour Python 2, utilisez la fonction intégrée reload () :

reload(module)

Pour Python 2 et 3.2–3.3, utilisez reload à partir du module imp :

import imp
imp.reload(module)

Mais impest déconseillé depuis la version 3.4 en faveur de importlib , utilisez donc:

import importlib
importlib.reload(module)

ou

from importlib import reload
reload(module)
49
goetzc

Le code suivant vous permet la compatibilité Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

Vous pouvez l’utiliser comme reload() dans les deux versions, ce qui simplifie les choses.

20
Matt Clarkson

La réponse acceptée ne gère pas le cas Y import X from. Ce code le gère, ainsi que le cas d'importation standard:

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

Dans le cas du rechargement, nous réaffectons les noms de premier niveau aux valeurs stockées dans le module nouvellement rechargé, qui les met à jour.

15
Joseph Garvin

C'est la manière moderne de recharger un module:

from importlib import reload

Il suffit de taper reload(MODULE_NAME), en remplaçant MODULE_NAME par le nom du module que vous souhaitez recharger.

Par exemple, reload(math) rechargera la fonction mathématique.

12
Richie Bendall

Si vous êtes non pas sur un serveur, mais développez et devez recharger fréquemment un module, voici un bon conseil.

Tout d’abord, assurez-vous d’utiliser l’excellent IPython Shell du projet Jupyter Notebook. Après avoir installé Jupyter, vous pouvez le lancer avec ipython, ou jupyter console, ou mieux encore, jupyter qtconsole, ce qui vous donnera une console Nice colorisée avec complétion de code dans tout système d'exploitation.

Maintenant dans votre shell, tapez:

%load_ext autoreload
%autoreload 2

Maintenant, à chaque fois vous exécutez votre script, vos modules seront rechargés. 

Au-delà du 2, il existe d'autres options de la magie de chargement automatique :

%autoreload
Reload all modules (except those excluded by %aimport) automatically now.

%autoreload 0
Disable automatic reloading.

%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.

%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.
10
neves

Pour ceux qui comme moi veulent décharger tous les modules (lors de l'exécution dans l'interpréteur Python sous Emacs ):

   for mod in sys.modules.values():
      reload(mod)

Plus d'informations à ce sujet dans Rechargement de modules Python.

6
Arkadiy

Enthought Traits a un module qui fonctionne assez bien pour cela. https://traits.readthedocs.org/fr/4.3.0/_modules/traits/util/refresh.html

Il rechargera tout module modifié et mettra à jour les autres modules et objets instanciés qui l'utilisent. Il ne fonctionne pas la plupart du temps avec les méthodes __very_private__ et peut s’étouffer en héritage de classe, mais il m’économise un temps fou à relancer l’application Host lors de l’écriture de PyQt guis, ou de choses exécutées dans des programmes tels que Maya ou Nuke . Cela ne fonctionne pas peut-être 20 à 30% du temps, mais cela reste incroyablement utile.

Le paquet d'Enthought ne recharge pas les fichiers au moment où ils changent - vous devez l'appeler explicitement - mais cela ne devrait pas être si difficile à mettre en œuvre si vous en avez vraiment besoin

5
flipthefrog

Ceux qui utilisent python 3 et rechargent depuis importlib.

Si vous rencontrez des problèmes tels que le module ne semble pas recharger ... C'est parce qu'il faut un peu de temps pour recompiler pyc (jusqu'à 60 secondes). J'écris cet indice juste que vous savez si vous avez rencontré ce type de problème.

4
PythonMan

2018-02-01

  1. le module foo doit être importé avec succès à l’avance. 
  2. from importlib import reload, reload(foo) 

31.5. importlib - Implémentation de l'import - Documentation Python 3.6.4

3
JawSaw

Autre option. Voyez que le code par défaut importlib.reload de Python ne fera que réimporter la bibliothèque transmise en tant qu’argument. Il ne sera pas recharger les bibliothèques que votre bibliothèque importe. Si vous avez modifié beaucoup de fichiers et que vous avez un package un peu complexe à importer, vous devez effectuer un rechargement complet

Si vous avez IPython ou Jupyter , vous pouvez utiliser une fonction pour recharger en profondeur toutes les bibliothèques:

from IPython.lib.deepreload import reload as dreload
dreload(foo)

Si vous n'avez pas Jupyter, installez-le avec cette commande dans votre shell:

pip3 install jupyter
3
neves

pour moi, dans le cas d’Abaqus, c’est la façon dont cela fonctionne ... Imaginez que votre fichier soit Class_VerticesEdges.py

sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:  
    del sys.modules['Class_VerticesEdges']
    print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])
1
Matt S

J'ai eu beaucoup de mal à essayer de recharger quelque chose dans Sublime Text, mais je pouvais enfin écrire cet utilitaire pour recharger des modules sur Sublime Text en fonction du code que sublime_plugin.py utilise pour recharger des modules.

Ce qui suit vous autorise à recharger des modules à partir de chemins d'accès avec des espaces sur leurs noms, puis, après le rechargement, vous pourrez simplement importer comme vous le faites habituellement.

def reload_module(full_module_name):
    """
        Assuming the folder `full_module_name` is a folder inside some
        folder on the python sys.path, for example, sys.path as `C:/`, and
        you are inside the folder `C:/Path With Spaces` on the file 
        `C:/Path With Spaces/main.py` and want to re-import some files on
        the folder `C:/Path With Spaces/tests`

        @param full_module_name   the relative full path to the module file
                                  you want to reload from a folder on the
                                  python `sys.path`
    """
    import imp
    import sys
    import importlib

    if full_module_name in sys.modules:
        module_object = sys.modules[full_module_name]
        module_object = imp.reload( module_object )

    else:
        importlib.import_module( full_module_name )

def run_tests():
    print( "\n\n" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
    reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )

    from .tests import semantic_linefeed_unit_tests
    from .tests import semantic_linefeed_manual_tests

    semantic_linefeed_unit_tests.run_unit_tests()
    semantic_linefeed_manual_tests.run_manual_tests()

if __== "__main__":
    run_tests()

Si vous vous lancez pour la première fois, cela devrait charger le module, mais si plus tard, vous pouvez à nouveau utiliser la méthode/fonction run_tests(), cela rechargera les fichiers de test. Avec Sublime Text (Python 3.3.6), cela se produit souvent car son interprète ne se ferme jamais (à moins que vous ne redémarriez Sublime Text, c’est-à-dire l’interprète Python3.3).

0
user

Une autre façon pourrait être d'importer le module dans une fonction. De cette façon, lorsque la fonction est terminée, le module est récupéré. 

0
hackbot89