Question Comment décharger (recharger) un module Python?


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

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

605
2018-01-13 00:33


origine


Réponses:


Vous pouvez recharger un module lorsqu'il a déjà été importé en utilisant le reload Fonction intégrée dans Python 2:

import foo

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

En Python 3, reload a été déplacé à la imp module. En 3.4, imp était déconseillé en faveur de importlib, et reload a été ajouté à ce dernier. Lorsque vous ciblez 3 ou plus tard, faites référence au module approprié lorsque vous appelez reload ou l'importer.

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

Pour citer les docs:

Le code des modules Python est recompilé et   le code au niveau du module est réexécuté,   définir un nouvel ensemble d'objets qui   sont liés à des noms dans le module   dictionnaire. La fonction init de   modules d'extension n'est pas appelé   deuxième fois. Comme avec tous les autres objets   en Python les anciens objets sont seulement   récupéré après leur nombre de références   tomber à zéro. Les noms dans le module   namespace sont mis à jour pour pointer vers tout   objets nouveaux ou modifiés. Autre   références aux anciens objets (tels que   noms externes au module) ne sont pas   rebondir pour se référer 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 noté dans votre question, vous devrez reconstruire Foo objets si le Foo classe réside dans le foo module.


553
2018-01-13 00:34



En Python 3.0-3.3 vous utiliseriez: imp.reload(module)

le BDFL a répondu cette question.

cependant, imp était déprécié en 3.4, en faveur de importlib (Merci @Stefan!).

je pensepar conséquent, vous utiliseriez maintenant importlib.reload(module), même si je ne suis pas sûr.


231
2017-10-10 13:36



Il peut être particulièrement difficile de supprimer un module s'il ne s'agit pas de 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   les 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 de la   module. Le "vide" du cru   (ne contenant rien) le module devrait être   ordures collectées après

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

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


75
2018-01-28 14:03



reload(module), mais seulement si c'est complètement autonome. Si quelque chose d'autre a une référence au module (ou tout 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 fonctionne pas entre différentes versions du même code.

Si vous avez des dépendances unidirectionnelles, vous devez également recharger tous les modules qui dépendent du module reloaded pour se débarrasser de toutes les références à l'ancien code. Et puis recharger les modules qui dépendent des modules rechargés, récursivement.

Si vous avez des dépendances circulaires, ce qui est très courant, par exemple lorsque vous devez recharger un paquet, vous devez décharger tous les modules du groupe en une fois. Tu ne peux pas faire ça avec reload() car il va ré-importer chaque module avant que ses dépendances aient été rafraîchies, permettant aux anciennes références de s'introduire dans de nouveaux modules.

La seule façon de le faire dans ce cas est de pirater sys.modules, ce qui n'est pas pris en charge. Vous devez passer par et supprimer chaque sys.modules entrée que vous vouliez recharger lors de la prochaine importation, et également supprimer les entrées dont les valeurs sont None pour résoudre un problème de mise en œuvre lié à la mise en cache des importations relatives en échec. Ce n'est pas très bien, mais tant que vous avez un ensemble de dépendances entièrement autonome qui ne laisse pas de références en dehors de son code, c'est faisable.

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


57
2018-01-13 12:53



if 'myModule' in sys.modules:  
    del sys.modules["myModule"]

52
2017-07-07 11:44



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

reload(module)

Pour Python 2 et 3.2-3.3, utilisez recharger depuis le module imp:

import imp
imp.reload(module)

Mais imp  est déprécié depuis la version 3.4 en faveur d'importlib, alors utilisez:

import importlib
importlib.reload(module)

ou

from importlib import reload
reload(module)

33
2017-08-09 17:28



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

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

Le vous pouvez l'utiliser comme reload() dans les deux versions, ce qui rend les choses plus simples.


19
2017-11-20 16:01



La réponse acceptée ne gère pas le cas Y d'importation X. 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 de rechargement, nous réattribuons les noms de niveau supérieur aux valeurs stockées dans le module nouvellement rechargé, ce qui les met à jour.


13
2017-09-27 23:30



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

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

Plus d'informations sont en Rechargement de modules Python.


6
2018-05-08 16:50



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 qui a été modifié et mettra à jour d'autres modules et objets instanciés qui l'utilisent. Ça ne marche pas la plupart du temps avec __very_private__ méthodes, et peut étouffer l'héritage de classe, mais cela 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 s'exécutent dans des programmes tels que Maya ou Nuke. Cela ne fonctionne peut-être pas 20-30% du temps, mais c'est toujours 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


5
2018-01-09 01:06



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

from importlib import reload as modulereload

Juste taper modulereload(MODULE_NAME), remplaçant MODULE_NAME avec le nom du module que vous voulez recharger.

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


5
2017-11-21 18:04