Comment décharger (recharger) un module?

797

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

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
Mark Harrison
la source
53
Astuce: "importer" ne signifie pas "charger", cela signifie "charger s'il n'est pas encore chargé et ensuite importer dans l'espace de noms".
Kos
3
la question ne doit pas inclure «décharger» car cela n'est pas encore possible en python - le rechargement est cependant un paradigme connu comme indiqué ci
robertmoggach
J'ai eu le même problème lors de l'utilisation d'un module dynamique dans l'application py2exe. Comme py2exe conserve toujours le bytecode dans le répertoire zip, le rechargement ne fonctionnait pas. Mais j'ai trouvé une solution de travail en utilisant le module import_file. Maintenant, ma demande fonctionne bien.
Pritam Pan
2
Que se passe-t-il si vous souhaitez "décharger" car le code essaie de supprimer un fichier .pyc?
darkgaze

Réponses:

795

Vous pouvez recharger un module lorsqu'il a déjà été importé à l'aide de la reloadfonction intégrée (Python 3.4+ uniquement) :

from importlib import reload  
import foo

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

En Python 3, a reloadété déplacé vers le impmodule. En 3.4, a impété déprécié en faveur de importlib, et a reloadété ajouté à ce dernier. Lorsque vous ciblez 3 ou une version ultérieure, faites référence au module approprié lors de l'appel reloadou importez-le.

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 modifications de code sans redémarrer le processus serveur lui-même.

Pour citer des documents:

Le code des modules Python est recompilé et le code au niveau du module est réexécuté, définissant un nouvel ensemble d'objets qui sont liés aux noms dans le dictionnaire du module. La fonction init des modules d'extension n'est pas appelée une deuxième fois. Comme pour tous les autres objets en Python, les anciens objets ne sont récupérés qu'après que leur nombre de références soit tombé à zéro. Les noms dans l'espace de noms du module sont mis à jour pour pointer vers tout objet nouveau ou modifié. Les autres références aux anciens objets (comme les noms externes au module) ne sont pas rebondies pour faire référence aux nouveaux objets et doivent être mises à jour dans chaque espace de noms où elles se produisent si cela est souhaité.

Comme vous l'avez noté dans votre question, vous devrez reconstruire des Fooobjets si la Fooclasse réside dans le foomodule.

cdleary
la source
10
En fait, le django dev serveur redémarre lui - même lorsque vous modifiez un fichier .. (il redémarre le serveur, et non seulement le module recharge)
Hasen
25
d'où vient cette fonction "is_changed"? je ne vois aucune documentation à ce sujet et il ne fonctionne pas dans mon environnement Python 3.1.3, ni dans 2.6.4.
jedmao
5
pas de cdleary, Django ne peut pas simplement utiliser reload: pyunit.sourceforge.net/notes/reloading.html
raylu
4
le rechargement n'est pas suffisant pour les modules avec des dépendances. Voir bobince ci-dessous: stackoverflow.com/a/438845/456878 . Cela m'a déjà mordu et perdu une bonne dizaine de minutes.
Doug Bradshaw
5
@jedmao @JamesDraper Je suis sûr que la is_changedfonction est juste une fonction arbitraire que vous auriez à écrire; ce n'est pas un intégré. Par exemple, il pourrait éventuellement ouvrir le fichier correspondant au module que vous importez et le différencier avec une version mise en cache pour voir s'il a changé.
James Mchugh
252

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

Le BDFL a répondu à cette question.

Cependant, a impété déprécié en 3.4, en faveur deimportlib (merci @Stefan! ).

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

Paul D. Waite
la source
23
Le débutant sincère est reconnaissant d'apprendre les nuances critiques entre Python 2 et 3.
Smandoli
24
imp.reload (imp) est-il valide?
Loïc Faure-Lacroix
2
@ LoïcFaure-Lacroix de la même manière reload(__builtins__)est valable en 2.x
JBernardo
1
@Tarrasch: c'est le module Python que vous souhaitez recharger, comme dans l'exemple de la question.
Paul D. Waite
3
@ LoïcFaure-Lacroix oui, imp peut se recharger.
Devyn Collier Johnson
92

Il peut être particulièrement difficile de supprimer un module s'il ne s'agit pas de Python pur.

Voici quelques informations de: Comment supprimer vraiment 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 qu'il sera difficile de se débarrasser du module. Le module local "vide" (ne contenant rien) doit être récupéré après

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

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

Gregg Lind
la source
4
Je viens de découvrir que si le module fait partie d'un package, vous devez également le supprimer ici:setattr(package, "empty", None)
u0b34a0f6ae
6
C'est la bonne solution, surtout si vous avez un package avec des modules imbriqués. reload()recharge uniquement le module le plus haut, et tout ce qu'il contient ne sera pas rechargé à moins que vous ne le supprimiez d'abord de sys.modules.
Cerin
73

reload(module), mais uniquement s'il est complètement autonome. Si quelque chose d'autre a une référence au module (ou à tout objet appartenant au module), 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 isinstancene pas fonctionner sur 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 se débarrasser de toutes les références à l'ancien code. Et puis rechargez 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 avez besoin de recharger un package, vous devez décharger tous les modules du groupe en une seule 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 aux anciennes références de se glisser dans les nouveaux modules.

La seule façon de le faire dans ce cas est de pirater sys.modules, ce qui n'est pas supporté. Vous devez parcourir et supprimer chaque sys.modulesentrée que vous souhaitez recharger lors de la prochaine importation, et également supprimer les entrées dont les valeurs Noneconcernent un problème d'implémentation lié à la mise en cache des importations relatives ayant échoué. Ce n'est pas terriblement agréable, 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. :-)

bobince
la source
1
Le téléchargement n'est-il pas spécifiquement conçu pour ce scénario?
Josh
@Josh: non, c'est pour recharger une arborescence de packages, et même alors cela ne fonctionne que tant que le package n'a pas de dépendances externes / circulaires.
bobince
1
Pouvez-vous élaborer la partie avec des Nonevaleurs parce que je rencontre exactement ce problème: je supprime des éléments de sys.moduleset après la réimportation de certaines dépendances importées None.
schlamar
@shclamar: Voir stackoverflow.com/questions/1958417/… (et les liens à partir de là) pour le fond. NoneJe ne sais pas (même en regardant le code import.c) comment les entrées ont réussi à revenir dans le mécanisme d'importation lorsque les «vraies» entrées ont été supprimées, et je n'arrive pas à y arriver sur 2.7; à l'avenir, ce n'est certainement plus un problème car les importations relatives implicites ont disparu. En attendant, la suppression de toutes les entrées avec Nonevaleur semble le corriger.
bobince
1
@Eliethesaiyan: parlez-vous de la reloadfonction? Il est intégré, vous n'avez pas besoin d'importer de bibliothèque.
bobince
63
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
Kumaresan
la source
3
+1. Mon objectif était d'exécuter des tests de nez en python. Après avoir chargé un module et renommé certaines fonctions, les anciens noms sont restés lors de l'appel nose.run(), même aprèsreload(my_module) %run my_module
Peter D
5
Si votre module importe ses propres sous-modules, vous devrez peut-être également les supprimer. Quelque chose comme [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
drevicko
Je ne pense pas que cela décharge le module. Sur Python 3.8: import sys; import json; del sys.modules['json']; print(json.dumps([1]))et le module json fonctionne toujours même s'il n'est plus dans les modules sys.modules.
Seperman
60

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

reload(module)

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

import imp
imp.reload(module)

Mais imp est déconseillé depuis la version 3.4 en faveur de l'importlib , alors utilisez:

import importlib
importlib.reload(module)

ou

from importlib import reload
reload(module)
goetzc
la source
2
pour gérer l'un de ces cas: from six import reload_module(besoin pip install sixde bien sûr d'abord)
Anentropic
@Anentropic: Il est judicieux de recommander l'utilisation du package six, mais la syntaxe est from six.moves import reload_module( doc )
x0s
23

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.

Matt Clarkson
la source
18

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

Joseph Garvin
la source
Remarqué un problème, globals () fait référence au module dans lequel vous définissez cette fonction, donc si vous la définissez dans un module différent de celui dans lequel vous l'appelez, cela ne fonctionne pas.
Joseph Garvin
Pour interactif, après >>> from X import Ypour recharger do>>> __import__('X', fromlist='Y')
Bob Stein
@ BobStein-VisiBone, existe-t-il un moyen de faire fonctionner cela quand fromlist='*'?
Mike C
Bonne question, je ne sais pas @MikeC. Soit dit en passant, j'ai tendance à cesser presque toute utilisation de fromdans les déclarations d'importation. Package.symbol juste import <package>et explicite dans le code. Sachez que cela n'est pas toujours possible ou souhaitable. (Voici une exception: à partir de la future import print_function.)
Bob Stein
Mike C: ce qui fonctionne pour moi c'estfoo = reload(foo); from foo import *
rampion
16

Voici la manière moderne de recharger un module:

from importlib import reload

Si vous souhaitez prendre en charge les versions de Python antérieures à 3.5, essayez ceci:

from sys import version_info
if version_info[0] < 3:
    pass # Python 2 has built in reload
elif version_info[0] == 3 and version_info[1] <= 4:
    from imp import reload # Python 3.0 - 3.4 
else:
    from importlib import reload # Python 3.5+

Pour l'utiliser, exécutez reload(MODULE)en remplaçant MODULEpar le module que vous souhaitez recharger.

Par exemple, reload(math)rechargera le mathmodule.

Richie Bendall
la source
4
Ou tout simplement faire from importlib import reload. Ensuite, vous pouvez le faire reload(MODULE_NAME). Il n'y a pas besoin de cette fonction.
pault
Je crois que modulereload(MODULE_NAME)c'est plus explicite que juste reload(MODULE_NAME)et a moins de chances d'entrer en conflit avec d'autres fonctions.
Richie Bendall
@RichieBendall Désolé, mais cette réponse est complètement fausse. La fonction reload () prend l'objet module, pas le nom du module ... Lisez les documents: docs.python.org/3/library/importlib.html#importlib.reload Et je suis d'accord avec @ pault - ce "en tant que modulereload" est superflu .
mbdevpl
J'ai changé ma réponse pour refléter votre opinion.
Richie Bendall
13

Si vous n'êtes pas sur un serveur, mais que vous développez et avez besoin de recharger fréquemment un module, voici un bon conseil.

Tout d'abord, assurez-vous d'utiliser l'excellent shell IPython du projet Jupyter Notebook. Après avoir installé Jupyter, vous pouvez le démarrer avec ipython, ou jupyter console, ou mieux encore jupyter qtconsole, qui vous donnera une belle console colorisée avec un code complet dans n'importe quel OS.

Maintenant dans votre shell, tapez:

%load_ext autoreload
%autoreload 2

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

Au-delà de 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.
neves
la source
7

Pour ceux comme moi qui 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 sont dans le rechargement des modules Python .

Peter Mortensen
la source
En fait, cela ne semble pas fonctionner de manière fiable (en 2.6) car tout sys.modules.values()n'est pas un module. Par exemple: >>> type (sys.modules.values ​​() [1]) <class 'email.LazyImporter'> Donc, si j'essaie d'exécuter ce code, il tombe (je sais que ce n'est pas censé être une solution pratique, juste le soulignant).
Francis Davey
Cela ne fonctionne même pas dans les pythons antérieurs - comme écrit. J'ai dû exclure certains noms. Je mettrai à jour la publication lorsque je déplacerai ce code sur mon nouvel ordinateur.
2
Fonctionne très bien en Python 2.7 après quelques modifications:if mod and mod.__name__ != "__main__": imp.reload(mod)
Czarek Tomczak
2
Cela fonctionne bien pour moi: importez imp [reload (m) pour m dans sys.modules.values ​​() si m et non " " dans m .__ nom et non imp.is_builtin (m .__ name__)]
Patrick Wolf
5

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. Cela ne fonctionne pas la plupart du temps avec des __very_private__méthodes et peut étouffer l'héritage de classe, mais cela me fait gagner beaucoup de temps sans avoir à redémarrer l'application hôte lors de l'écriture de PyQt, ou des choses qui s'exécutent à l'intérieur de programmes tels que Maya ou Nuke. Cela ne fonctionne peut-être pas 20 à 30% du temps, mais c'est toujours incroyablement utile.

Le package 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

flipthefrog
la source
5

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'il faut du temps pour recompiler pyc (jusqu'à 60 sec). J'écris cet indice juste pour savoir si vous avez rencontré ce genre de problème.

PythonMan
la source
3

Autre option. Vérifiez que Python par défaut importlib.reloadne fera que réimporter la bibliothèque passée en argument. Il ne rechargera pas les bibliothèques que votre bibliothèque importe. Si vous avez modifié beaucoup de fichiers et que vous avez un package quelque peu complexe à importer, vous devez effectuer un rechargement en profondeur .

Si vous avez installé 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
neves
la source
Ce dreload Ipython et reload () de importlib se plaignent reload() argument must be module. J'utilise une importation de fonction personnalisée et ne semble pas fonctionner. L'utilisation de modules intégrés fonctionne. :-( c'est une perte de temps de recharger iPython pour chaque petite modification que j'ai apportée à mon code ...
m3nda
2

Modifier (réponse V2)

La solution d'avant est bonne pour obtenir simplement les informations de réinitialisation, mais elle ne changera pas toutes les références (plus que reloadmais moins que nécessaire). Pour définir également toutes les références, j'ai dû aller dans le garbage collector et y réécrire les références. Maintenant ça marche comme un charme!

Notez que cela ne fonctionnera pas si le GC est éteint, ou si le rechargement de données qui n'est pas surveillé par le GC. Si vous ne voulez pas jouer avec le GC, la réponse originale pourrait vous suffire.

Nouveau code:

import importlib
import inspect
import gc
from weakref import ref


def reset_module(module, inner_modules_also=True):
    """
    This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
    module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
    to be the reloaded-module's
    :param module: The module to reload (module reference, not the name)
    :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
    """

    # For the case when the module is actually a package
    if inner_modules_also:
        submods = {submod for _, submod in inspect.getmembers(module)
                   if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
        for submod in submods:
            reset_module(submod, True)

    # First, log all the references before reloading (because some references may be changed by the reload operation).
    module_tree = _get_tree_references_to_reset_recursively(module, module.__name__)

    new_module = importlib.reload(module)
    _reset_item_recursively(module, module_tree, new_module)


def _update_referrers(item, new_item):
    refs = gc.get_referrers(item)

    weak_ref_item = ref(item)
    for coll in refs:
        if type(coll) == dict:
            enumerator = coll.keys()
        elif type(coll) == list:
            enumerator = range(len(coll))
        else:
            continue

        for key in enumerator:

            if weak_ref_item() is None:
                # No refs are left in the GC
                return

            if coll[key] is weak_ref_item():
                coll[key] = new_item

def _get_tree_references_to_reset_recursively(item, module_name, grayed_out_item_ids = None):
    if grayed_out_item_ids is None:
        grayed_out_item_ids = set()

    item_tree = dict()
    attr_names = set(dir(item)) - _readonly_attrs
    for sub_item_name in attr_names:

        sub_item = getattr(item, sub_item_name)
        item_tree[sub_item_name] = [sub_item, None]

        try:
            # Will work for classes and functions defined in that module.
            mod_name = sub_item.__module__
        except AttributeError:
            mod_name = None

        # If this item was defined within this module, deep-reset
        if (mod_name is None) or (mod_name != module_name) or (id(sub_item) in grayed_out_item_ids) \
                or isinstance(sub_item, EnumMeta):
            continue

        grayed_out_item_ids.add(id(sub_item))
        item_tree[sub_item_name][1] = \
            _get_tree_references_to_reset_recursively(sub_item, module_name, grayed_out_item_ids)

    return item_tree


def _reset_item_recursively(item, item_subtree, new_item):

    # Set children first so we don't lose the current references.
    if item_subtree is not None:
        for sub_item_name, (sub_item, sub_item_tree) in item_subtree.items():

            try:
                new_sub_item = getattr(new_item, sub_item_name)
            except AttributeError:
                # The item doesn't exist in the reloaded module. Ignore.
                continue

            try:
                # Set the item
                _reset_item_recursively(sub_item, sub_item_tree, new_sub_item)
            except Exception as ex:
                pass

    _update_referrers(item, new_item)

Réponse originale

Comme écrit dans la réponse de @ bobince, s'il y a déjà une référence à ce module dans un autre module (surtout s'il a été importé avec le asmot - clé like import numpy as np), cette instance ne sera pas écrasée.

Cela s'est avéré assez problématique pour moi lors de l'application de tests qui nécessitaient un état "net" des modules de configuration, j'ai donc écrit une fonction nommée reset_modulequi utilise importlibla reloadfonction de et écrase récursivement tous les attributs du module déclaré. Il a été testé avec Python version 3.6.

import importlib
import inspect
from enum import EnumMeta

_readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
               '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
               '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
               '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
               '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
               '__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
               '__basicsize__', '__base__'}


def reset_module(module, inner_modules_also=True):
    """
    This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
    module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
    to be the reloaded-module's
    :param module: The module to reload (module reference, not the name)
    :param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
    """

    new_module = importlib.reload(module)

    reset_items = set()

    # For the case when the module is actually a package
    if inner_modules_also:
        submods = {submod for _, submod in inspect.getmembers(module)
                   if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
        for submod in submods:
            reset_module(submod, True)

    _reset_item_recursively(module, new_module, module.__name__, reset_items)


def _reset_item_recursively(item, new_item, module_name, reset_items=None):
    if reset_items is None:
        reset_items = set()

    attr_names = set(dir(item)) - _readonly_attrs

    for sitem_name in attr_names:

        sitem = getattr(item, sitem_name)
        new_sitem = getattr(new_item, sitem_name)

        try:
            # Set the item
            setattr(item, sitem_name, new_sitem)

            try:
                # Will work for classes and functions defined in that module.
                mod_name = sitem.__module__
            except AttributeError:
                mod_name = None

            # If this item was defined within this module, deep-reset
            if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
                    or isinstance(sitem, EnumMeta):  # Deal with enums
                continue

            reset_items.add(id(sitem))
            _reset_item_recursively(sitem, new_sitem, module_name, reset_items)
        except Exception as ex:
            raise Exception(sitem_name) from ex

Remarque: à utiliser avec précaution! Leur utilisation sur des modules non périphériques (modules qui définissent des classes utilisées en externe, par exemple) peut entraîner des problèmes internes en Python (tels que des problèmes de pickling / un-pickling).

EZLearner
la source
1

pour moi pour le cas d'Abaqus c'est la façon dont ça marche. Imaginez que votre fichier 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'])
Matt S
la source
Cette réponse est une copie directe d'ici: ebanshi.cc/questions/1942/…
SiHa
0

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 en fonction du code sublime_plugin.pyutilisé pour recharger les modules.

Ceci ci-dessous vous permet de recharger les 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 se produit souvent car son interprète ne se ferme jamais (sauf si vous redémarrez Sublime Text, c'est-à-dire l' Python3.3interpréteur).

utilisateur
la source
-1

Une autre façon pourrait être d'importer le module dans une fonction. De cette façon, lorsque la fonction se termine, le module récupère les ordures.

hackbot89
la source
4
Le module ne récupérera jamais les ordures car une référence globale est conservée au moins dans sys.modules.
Tous les travailleurs sont essentiels