Comment décharger (recharger) un module Python?
j'ai un serveur Python qui fonctionne depuis longtemps et je voudrais pouvoir mettre à jour un service sans redémarrer le serveur. Quelle est la meilleure façon de faire cela?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
19 réponses
vous pouvez recharger un module alors qu'il a déjà été importé en utilisant la fonction reload
builtin en Python 2:
import foo
while True:
# Do some things.
if is_changed(foo):
foo = reload(foo)
en Python 3, reload
a été déplacé dans le module imp
. Au 3.4, imp
a été déprécié en faveur de importlib
, et reload
a été ajouté à ce dernier. Lorsque vous ciblez 3 ou plus, référez - vous au module approprié lorsque vous appelez reload
ou importez-le.
je pense que c'est ce que vous voulez. Les serveurs Web comme le serveur de développement de Django utilisent ceci pour que vous puissiez voir les effets de vos modifications de code sans redémarrer le processus de serveur lui-même.
pour citer les docs:
le code des modules Python est recompilé et le code au niveau du module a été réexaminé, définition d'un nouvel ensemble d'objets qui sont liés aux noms dans le module dictionnaire. La fonction init de les modules d'extension ne sont pas appelés deuxième temps. Comme pour tous les autres objets en Python les vieux objets sont seulement récupérées après leur comptage de référence tomber à zéro. Les noms dans le module espace 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 les noms externes au module) ne sont pas rebond pour consulter les nouveaux objets et doit être mis à jour chaque espace de noms où ils se produisent, si cela est souhaité.
comme vous l'avez noté dans votre question, vous devrez reconstruire les objets Foo
si la classe Foo
réside dans le module foo
.
en Python 3.0-3.3 vous utiliseriez: imp.reload(module)
Le BDFL a répondu à cette question.
cependant, imp
a été déprécié en 3.4, en faveur de importlib
(merci @Stefan! ).
je penser , par conséquent, vous feriez maintenant utiliser importlib.reload(module)
, bien que je ne sois pas sûr.
il peut être particulièrement difficile de supprimer un module s'il n'est pas Python pur.
voici quelques informations de: Comment puis-je vraiment supprimer un module importé?
vous pouvez utiliser sys.getrefcount () pour connaître le nombre réel de référence.
>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3
Les nombressupérieurs à 3 indiquent que il sera difficile de se débarrasser de la module. Le homegrown "vide" (ne contenant rien) module devrait être déchets collectés après
>>> del sys.modules["empty"]
>>> del empty
comme la troisième référence est un artefact de la fonction getrefcount ().
reload(module)
, mais seulement si c'est complètement autonome. Si quelque chose d'autre a une référence au module (ou n'importe quel objet appartenant au module), alors vous obtiendrez des erreurs subtiles et curieuses causées par l'ancien code qui traîne autour plus longtemps que vous prévu, et des choses comme isinstance
ne fonctionne pas à travers différentes versions du 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 vous en débarrasser. toutes les références à l'ancien code. Et puis recharger les modules qui dépendent des modules rechargés, de façon récursive.
si vous avez des dépendances circulaires, ce qui est très courant par exemple quand vous avez affaire à recharger un paquet, vous devez décharger tous les modules du groupe en une seule fois. Vous ne pouvez pas faire cela avec reload()
parce qu'il va réimporter chaque module avant que ses dépendances aient été rafraîchies, permettant aux anciennes références de se glisser dans de nouveaux modules.
la seule façon de le faire dans ce cas est de hacker sys.modules
, qui est en quelque sorte non supporté. Vous devez passer par et supprimer chaque entrée sys.modules
que vous voulez recharger sur la prochaine importation, et aussi supprimer les entrées dont les valeurs sont None
pour traiter d'un problème de mise en œuvre à faire avec la mise en cache des importations relatives. Ce n'est pas très agréable, mais tant que vous avez un ensemble complet de dépendances qui ne laisse pas de références en dehors de sa base de données, c'est faisable.
Il est probablement préférable de redémarrer le serveur. :- )
pour Python 2 utiliser la fonction intégrée recharger () :
reload(module)
pour Python 2 et 3.2–3.3 utiliser recharger à partir du module imp :
import imp
imp.reload(module)
mais imp
est déprécié depuis la version 3.4 en faveur de l'importlib , donc utiliser:
import importlib
importlib.reload(module)
ou
from importlib import reload
reload(module)
le code suivant vous permet une 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 rend les choses plus simples.
la réponse acceptée ne gère pas le cas de x import Y. 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éattribuons les noms de niveau supérieur aux valeurs stockées dans le module nouvellement rechargé, qui les met à jour.
C'est la façon moderne de recharger un module:
from importlib import reload
tapez juste reload(MODULE_NAME)
, en remplaçant MODULE_NAME
par le nom du module que vous voulez recharger.
par exemple, reload(math)
rechargera la fonction mathématique.
pour ceux comme moi qui veulent décharger tous les modules (en tournant dans l'interpréteur Python sous Emacs ):
for mod in sys.modules.values():
reload(mod)
plus d'informations dans recharger les modules Python .
si vous êtes pas dans un serveur, mais en développement et avez besoin de recharger fréquemment un module, voici un bon conseil.
tout d'abord , assurez-vous que vous utilisez l'excellent IPython shell , du projet de carnet Jupyter. Après avoir installé Jupyter, vous pouvez le démarrer avec ipython
, ou jupyter console
, ou encore mieux, jupyter qtconsole
, ce qui vous donnera une belle console colorisée avec le code achèvement dans tous les OS.
maintenant dans votre coquille, tapez:
%load_ext autoreload
%autoreload 2
maintenant, chaque fois que vous exécutez votre script, vos modules seront rechargés.
au-delà du 2
, il y a 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.
Enthought Traits a un module qui fonctionne assez bien pour cela. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html
il rechargera tout module qui a été 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 étouffer sur l'héritage de classe, mais il me sauve des quantités folles de temps d'avoir à redémarrer l'application hôte lors de L'écriture PyQt guis, ou des choses qui court à l'intérieur de programmes tels que Maya ou Nuke. Ça ne marche peut-être pas 20-30% du temps, mais c'est quand même incroyablement utile.
le paquet de Enthought ne recharge pas les fichiers au moment où ils changent - vous devez l'appeler explicitement - mais cela ne devrait pas être si difficile à implémenter si vous en avez vraiment besoin
2018-02-01
- module
foo
doit être importé avec succès à l'avance. -
from importlib import reload
,reload(foo)
31.5. importlib-la mise en œuvre d'import-Python 3.6.4 documentation
ceux qui utilisent python 3 et rechargent depuis importlib.
si vous avez des problèmes comme il semble que le module ne se recharge pas... C'est parce qu'elle a besoin de temps pour recompiler pyc (jusqu'à 60 secondes).J'écris cet indice juste que vous savez si vous avez expérimenté ce genre de problème.
pour moi, pour le cas d'Abaqus c'est la façon dont il fonctionne. Imaginez que votre dossier est 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'])
autre option. Voyez que la valeur par défaut de Python importlib.reload
va réimporter la bibliothèque passée en argument. ne sera pas recharger les bibliothèques que votre lib importation. Si vous avez changé beaucoup de fichiers et que vous avez un paquet assez complexe à importer, vous devez faire un Deep reload .
si vous avez IPython ou Jupyter installé, vous pouvez utiliser une fonction pour recharger tous libs:
from IPython.lib.deepreload import reload as dreload
dreload(foo)
si vous n'avez pas Jupyter, installez-le avec cette commande dans votre coquille:
pip3 install jupyter
j'ai eu beaucoup de mal à essayer de recharger quelque chose à L'intérieur de Sublime Text, mais finalement j'ai pu écrire cet utilitaire pour recharger des modules sur Sublime Text basé sur le code sublime_plugin.py
utilise pour recharger des modules.
ce qui suit vous permet de recharger des modules à partir de chemins avec des espaces sur leurs noms, puis plus tard après le rechargement vous pouvez 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 __name__ == "__main__":
run_tests()
si vous exécutez pour la première fois, cela devrait charger le module, mais si plus tard, vous pouvez à nouveau la méthode/fonction run_tests()
il rechargera les fichiers de tests. Avec Sublime Text ( Python 3.3.6
) cela arrive souvent parce que son interpréteur ne ferme jamais (à moins que vous ne redémarriez Sublime Text, i.e., l'interpréteur Python3.3
).
une Autre façon serait d'importer le module dans une fonction. De cette façon, lorsque la fonction est terminée, le module reçoit les ordures.
l'opération unload
peut être facilement effectuée comme ceci:
import pythonlib
del pythonlib
vous n'aurez plus rien à voir avec cette bibliothèque.