Wie entlade ich ein Modul (lade es neu)?

797

Ich habe einen lang laufenden Python-Server und möchte einen Dienst aktualisieren können, ohne den Server neu zu starten. Was ist der beste Weg, dies zu tun?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
Mark Harrison
quelle
53
Anmerkungstipp: "Importieren" bedeutet nicht "Laden", sondern "Laden, wenn noch nicht geladen, und dann in den Namespace importieren".
Kos
3
die frage sollte nicht 'entladen' enthalten, da dies in python noch nicht möglich ist
reload
Ich hatte das gleiche Problem bei der Verwendung eines dynamischen Moduls in der py2exe-App. Da py2exe immer den Bytecode im Zip-Verzeichnis behält, funktionierte das Neuladen nicht. Aber ich habe eine funktionierende Lösung mit dem Modul import_file gefunden. Jetzt funktioniert meine Anwendung einwandfrei.
Pritam Pan
2
Was ist, wenn Sie "entladen" möchten, weil der Code versucht, eine .pyc-Datei zu löschen?
Darkgaze

Antworten:

791

Sie können ein Modul neu laden, wenn es bereits importiert wurde, indem Sie die reloadintegrierte Funktion verwenden (nur Python 3.4+) :

from importlib import reload  
import foo

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

In Python 3 reloadwurde in das impModul verschoben . In 3.4 impwurde zugunsten von abgelehnt importlibund reloadzu letzterem hinzugefügt. Wenn Sie auf 3 oder höher abzielen, verweisen Sie beim Aufrufen entweder auf das entsprechende Modul reloadoder importieren Sie es.

Ich denke, das ist was du willst. Webserver wie der Entwicklungsserver von Django verwenden dies, damit Sie die Auswirkungen Ihrer Codeänderungen sehen können, ohne den Serverprozess selbst neu zu starten.

Um aus den Dokumenten zu zitieren:

Der Code der Python-Module wird neu kompiliert und der Code auf Modulebene erneut ausgeführt, wodurch eine neue Gruppe von Objekten definiert wird, die an Namen im Wörterbuch des Moduls gebunden sind. Die Init-Funktion von Erweiterungsmodulen wird nicht ein zweites Mal aufgerufen. Wie bei allen anderen Objekten in Python werden die alten Objekte erst zurückgefordert, nachdem ihre Referenzanzahl auf Null gefallen ist. Die Namen im Modul-Namespace werden aktualisiert, um auf neue oder geänderte Objekte zu verweisen. Andere Verweise auf die alten Objekte (z. B. Namen außerhalb des Moduls) werden nicht zurückgebunden, um auf die neuen Objekte zu verweisen, und müssen in jedem Namespace aktualisiert werden, in dem sie auftreten, wenn dies gewünscht wird.

Wie Sie in Ihrer Frage festgestellt haben, müssen Sie FooObjekte rekonstruieren , wenn sich die FooKlasse im fooModul befindet.

cdleary
quelle
10
Tatsächlich startet sich der Django Dev Server neu, wenn Sie eine Datei ändern. (Er startet den Server neu und lädt nicht nur das Modul neu.)
Hasen
25
Woher kommt diese "is_changed" -Funktion? Ich sehe keine Dokumentation dazu und es läuft nicht in meiner Python 3.1.3-Umgebung, noch läuft es in 2.6.4.
jedmao
5
nein cdleary, Django kann nicht einfach reload
raylu
14
@ BartoszKP wenn Xkein Modul ist, können Sieimport sys; reload(sys.modules[X.__module__])
drevicko
5
@jedmao @JamesDraper Ich bin mir ziemlich sicher, dass die is_changedFunktion nur eine beliebige Funktion ist, die Sie schreiben müssten. Es ist kein eingebautes. Beispielsweise könnte es möglicherweise die Datei öffnen, die dem zu importierenden Modul entspricht, und sie mit einer zwischengespeicherten Version unterscheiden, um festzustellen, ob sie sich geändert hat.
James Mchugh
252

In Python 3.0–3.3 würden Sie Folgendes verwenden: imp.reload(module)

Die BDFL hat geantwortet diese Frage .

Allerdings impwurde in 3.4 zugunsten vonimportlib (danke @Stefan! ) Veraltet .

Ich denke , deshalb würden Sie jetzt verwenden importlib.reload(module), obwohl ich nicht sicher bin.

Paul D. Waite
quelle
23
Der ernsthafte Neuling ist dankbar, über kritische Nuancen zwischen Python 2 und 3 zu lernen.
Smandoli
24
ist imp.reload (imp) gültig?
Loïc Faure-Lacroix
2
@ LoïcFaure-Lacroix der gleiche Weg reload(__builtins__)ist gültig in 2.x
JBernardo
1
@Tarrasch: Es ist das Python-Modul, das Sie neu laden möchten, wie im Beispiel in der Frage.
Paul D. Waite
3
@ LoïcFaure-Lacroix ja, imp kann sich neu laden.
Devyn Collier Johnson
92

Es kann besonders schwierig sein, ein Modul zu löschen, wenn es nicht reines Python ist.

Hier einige Informationen von: Wie lösche ich ein importiertes Modul wirklich?

Mit sys.getrefcount () können Sie die tatsächliche Anzahl der Referenzen ermitteln.

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

Zahlen größer als 3 zeigen an, dass es schwierig sein wird, das Modul loszuwerden. Das selbstgezogene "leere" (nichts enthaltende) Modul sollte nach dem Sammeln von Müll gesammelt werden

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

als dritte Referenz ist ein Artefakt der Funktion getrefcount ().

Gregg Lind
quelle
4
Ich habe gerade festgestellt, dass das Modul, wenn es Teil eines Pakets ist, auch dort gelöscht werden muss:setattr(package, "empty", None)
u0b34a0f6ae
6
Dies ist die richtige Lösung, insbesondere wenn Sie ein Paket mit verschachtelten Modulen haben. reload()Lädt nur das oberste Modul neu, und alles, was sich darin befindet, wird nicht neu geladen, es sei denn, Sie löschen es zuerst aus sys.modules.
Cerin
73

reload(module), aber nur, wenn es völlig eigenständig ist. Wenn irgendetwas anderes einen Verweis auf das Modul (oder ein zum Modul gehörendes Objekt) enthält, werden subtile und merkwürdige Fehler angezeigt, die dadurch verursacht werden, dass der alte Code länger als erwartet herumhängt und Dinge wie das isinstanceNicht-Arbeiten in verschiedenen Versionen des Moduls gleicher Code.

Wenn Sie Einwegabhängigkeiten haben, müssen Sie auch alle Module neu laden, die vom neu geladenen Modul abhängen, um alle Verweise auf den alten Code zu entfernen. Laden Sie dann die Module, die von den neu geladenen Modulen abhängen, rekursiv neu.

Wenn Sie zirkuläre Abhängigkeiten haben, was beispielsweise beim erneuten Laden eines Pakets sehr häufig vorkommt, müssen Sie alle Module in der Gruppe auf einmal entladen. Das kann man nicht machenreload() da jedes Modul erneut importiert wird, bevor seine Abhängigkeiten aktualisiert wurden, sodass sich alte Referenzen in neue Module einschleichen können.

Die einzige Möglichkeit, dies in diesem Fall zu tun, ist das Hacken sys.modules, was nicht unterstützt wird. Sie sys.modulesmüssten jeden Eintrag löschen, den Sie beim nächsten Import neu laden möchten, und auch Einträge löschen, deren Werte sindNone ein Implementierungsproblem im Zusammenhang mit dem Zwischenspeichern fehlgeschlagener relativer Importe behandeln sollen. Es ist nicht besonders schön, aber solange Sie eine vollständig in sich geschlossene Reihe von Abhängigkeiten haben, die keine Referenzen außerhalb der Codebasis belassen, ist es funktionsfähig.

Es ist wahrscheinlich am besten, den Server neu zu starten. :-)

Bobince
quelle
1
Ist Dreload nicht speziell für dieses Szenario?
Josh
@Josh: Nein, es dient zum erneuten Laden eines Paketbaums und funktioniert auch dann nur, solange das Paket keine externen / zirkulären Abhängigkeiten aufweist.
Bobince
1
Können Sie das Teil mit NoneWerten ausarbeiten , da ich genau auf dieses Problem stoße: Ich lösche Elemente aus sys.modulesund nach dem erneuten Import sind einige importierte Abhängigkeiten None.
schlamar
@shclamar: Hintergrundinformationen finden Sie unter stackoverflow.com/questions/1958417/… (und den Links von dort). Es ist mir unklar (selbst wenn ich mir den import.c-Code ansehe), wie die NoneEinträge den Importmechanismus durchlaufen haben, als die "echten" Einträge gelöscht wurden, und ich kann es anscheinend nicht in 2.7 schaffen. In Zukunft ist dies sicherlich kein Problem mehr, da implizite relative Importe weg sind. In der Zwischenzeit Nonescheint das Löschen aller Einträge mit Wert das Problem zu beheben.
Bobince
1
@ Eliethesaiyan: meinst du die reloadFunktion? Es ist integriert, Sie müssen keine Bibliothek importieren.
Bobince
63
if 'myModule' in sys.modules:  
    del sys.modules["myModule"]
Kumaresan
quelle
3
+1. Mein Ziel war es, Nasentests in Python durchzuführen. Nachdem ich ein Modul geladen und einige Funktionen umbenannt hatte, blieben die alten Namen beim Aufruf nose.run()auch nachreload(my_module) %run my_module
Peter D
5
Wenn Ihr Modul eigene Submodule importiert, müssen Sie diese möglicherweise auch löschen. So etwas wie [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
Drevicko
Ich glaube nicht, dass das Modul entladen wird. Unter Python 3.8: import sys; import json; del sys.modules['json']; print(json.dumps([1]))und json funktioniert das Modul immer noch, obwohl es nicht mehr in den sys.modules enthalten ist.
Seperman
60

Verwenden Sie für Python 2 die integrierte Funktion reload () :

reload(module)

Verwenden Sie für Python 2 und 3.2–3.3 reload from module imp :

import imp
imp.reload(module)

Aber imp ist veraltet , da Version 3.4 für importlib , so verwenden:

import importlib
importlib.reload(module)

oder

from importlib import reload
reload(module)
goetzc
quelle
2
um einen dieser Fälle zu behandeln: from six import reload_module(muss pip install sixnatürlich zuerst)
Anentropic
@Anentropic: Es ist ein guter Rat, die Verwendung von sechs Paketen zu empfehlen, aber die Syntax ist from six.moves import reload_module( doc )
x0s
23

Mit dem folgenden Code können Sie Python 2/3 kompatibel machen:

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

Sie können es wie reload()in beiden Versionen verwenden, was die Sache einfacher macht.

Matt Clarkson
quelle
18

Die akzeptierte Antwort behandelt den Fall von X-Import Y nicht. Dieser Code behandelt es und den Standardimportfall auch:

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

Im Fall des erneuten Ladens weisen wir die Namen der obersten Ebene den Werten zu, die im neu geladenen Modul gespeichert sind, wodurch sie aktualisiert werden.

Joseph Garvin
quelle
Globals () hat ein Problem festgestellt und bezieht sich auf das Modul, in dem Sie diese Funktion definieren. Wenn Sie es also in einem anderen Modul definieren als dem, in dem Sie es aufrufen, funktioniert dies nicht.
Joseph Garvin
Für interaktive, nach >>> from X import Ydem Nachladen tun>>> __import__('X', fromlist='Y')
Bob Stein
@ BobStein-VisiBone, gibt es eine Möglichkeit, dass dies funktioniert, wenn fromlist='*'?
Mike C
Gute Frage, weiß nicht @MikeC. Übrigens neige ich dazu, fast jede Verwendung fromin Importanweisungen einzustellen . Nur krasse import <package>und explizite package.symbol im Code. Beachten Sie, dass dies möglicherweise nicht immer möglich oder wünschenswert ist. (Hier ist eine Ausnahme: von zukünftigen Import print_function.)
Bob Stein
Mike C: Was für mich funktioniert, istfoo = reload(foo); from foo import *
Rampion
16

Dies ist die moderne Art, ein Modul neu zu laden:

from importlib import reload

Wenn Sie Versionen von Python unterstützen möchten, die älter als 3.5 sind, versuchen Sie Folgendes:

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+

Um es zu verwenden, führen Sie es aus reload(MODULE)und ersetzen Sie esMODULE durch das Modul, das Sie neu laden möchten.

Zum Beispiel reload(math)wird das mathModul neu geladen .

Richie Bendall
quelle
4
Oder einfach tun from importlib import reload. Dann können Sie tun reload(MODULE_NAME). Diese Funktion ist nicht erforderlich.
pault
Ich glaube, es modulereload(MODULE_NAME)ist mehr selbsterklärend als nur reload(MODULE_NAME)und hat eine geringere Wahrscheinlichkeit, mit anderen Funktionen in Konflikt zu geraten.
Richie Bendall
@RichieBendall Sorry, aber diese Antwort ist völlig falsch. Die Funktion reload () verwendet das Modulobjekt , nicht den Modulnamen ... Lesen Sie die Dokumente: docs.python.org/3/library/importlib.html#importlib.reload Und ich stimme @ pault zu - dies "als modulereload" ist überflüssig .
mbdevpl
Ich habe meine Antwort geändert, um Ihre Meinung widerzuspiegeln.
Richie Bendall
13

Wenn Sie sich nicht auf einem Server befinden, aber ein Modul entwickeln und häufig neu laden müssen, finden Sie hier einen guten Tipp.

Stellen Sie zunächst sicher, dass Sie die hervorragende IPython-Shell aus dem Jupyter Notebook-Projekt verwenden. Nach der Installation von Jupyter können Sie mit ipythonoder jupyter consoleoder noch besser beginnen.jupyter qtconsole , wodurch Sie eine schöne farbige Konsole mit Code-Vervollständigung in jedem Betriebssystem erhalten.

Geben Sie nun in Ihrer Shell Folgendes ein:

%load_ext autoreload
%autoreload 2

Jetzt jedes Mal Sie Ihr Skript ausführen, werden Ihre Module neu geladen.

Darüber hinaus 2gibt es andere Optionen der Autoreload-Magie :

%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
quelle
7

Für diejenigen wie mich, die alle Module entladen möchten (wenn sie im Python-Interpreter unter Emacs ausgeführt werden ):

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

Weitere Informationen finden Sie unter Reloading Python-Module .

Peter Mortensen
quelle
Eigentlich scheint das nicht zuverlässig zu funktionieren (in 2.6), weil nicht alles in sys.modules.values()einem Modul ist. Zum Beispiel: >>> type (sys.modules.values ​​() [1]) <class 'email.LazyImporter'> Wenn ich also versuche, diesen Code auszuführen, fällt er um (ich weiß, dass er nicht als praktische Lösung gedacht ist, nur darauf hinweisen).
Francis Davey
Es funktioniert nicht einmal in früheren Pythons - wie geschrieben. Ich musste einige Namen ausschließen. Ich werde den Beitrag aktualisieren, wenn ich diesen Code auf meinen neuen Computer verschiebe.
2
Funktioniert gut in Python 2.7 nach einigen Änderungen:if mod and mod.__name__ != "__main__": imp.reload(mod)
Czarek Tomczak
2
Dies funktioniert gut für mich: import imp [reload (m) für m in sys.modules.values ​​() wenn m und nicht " " in m .__ name und nicht imp.is_builtin (m .__ name__)]
Patrick Wolf
5

Enthought Traits hat ein Modul, das dafür ziemlich gut funktioniert. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Es wird jedes Modul, das geändert wurde, neu laden und andere Module und instanziierte Objekte aktualisieren, die es verwenden. Es funktioniert die meiste Zeit nicht mit __very_private__Methoden und kann an der Klassenvererbung ersticken, aber es erspart mir verrückte Zeit, die Host-Anwendung beim Schreiben von PyQt-Guis neu starten zu müssen, oder Dinge, die in Programmen wie Maya oder Nuke ausgeführt werden. Es funktioniert vielleicht 20-30% der Zeit nicht, aber es ist immer noch unglaublich hilfreich.

Das Paket von Enthought lädt Dateien nicht neu, sobald sie sich ändern - Sie müssen es explizit aufrufen -, aber das sollte nicht allzu schwer zu implementieren sein, wenn Sie es wirklich brauchen

Flipthefrog
quelle
5

Diejenigen, die Python 3 verwenden und von importlib neu laden.

Wenn Sie Probleme haben, wie es scheint, dass das Modul nicht neu geladen wird ... Das liegt daran, dass es einige Zeit braucht, um pyc neu zu kompilieren (bis zu 60 Sekunden). Ich schreibe diesen Hinweis nur, damit Sie wissen, ob Sie diese Art von Problem haben.

PythonMan
quelle
3

Andere Option. Beachten Sie, dass Python standardmäßig importlib.reloaddie als Argument übergebene Bibliothek nur erneut importiert. Die von Ihrer Bibliothek importierten Bibliotheken werden nicht neu geladen. Wenn Sie viele Dateien geändert haben und ein etwas komplexes Paket importieren müssen, müssen Sie ein tiefes Neuladen durchführen .

Wenn Sie IPython oder Jupyter installiert haben, können Sie eine Funktion verwenden, um alle Bibliotheken tief zu laden:

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

Wenn Sie Jupyter nicht haben, installieren Sie es mit diesem Befehl in Ihrer Shell:

pip3 install jupyter
neves
quelle
Sowohl dieses Ipython-Dreload als auch reload () von importlib beschweren sich reload() argument must be module. Ich verwende einen benutzerdefinierten Funktionsimport und scheint nicht zu funktionieren. Die Verwendung von integrierten Modulen funktioniert. :-( Es ist Zeitverschwendung, iPython für jede kleine Änderung, die ich an meinem Code vorgenommen habe, neu zu
laden
2

Bearbeiten (Antwort V2)

Die vorherige Lösung eignet sich nur zum Abrufen der Rücksetzinformationen, ändert jedoch nicht alle Referenzen (mehr als, reloadaber weniger als erforderlich). Um auch alle Referenzen zu setzen, musste ich in den Garbage Collector gehen und die Referenzen dort neu schreiben. Jetzt funktioniert es wie ein Zauber!

Beachten Sie, dass dies nicht funktioniert, wenn der GC ausgeschaltet ist oder wenn Daten neu geladen werden, die nicht vom GC überwacht werden. Wenn Sie sich nicht mit dem GC anlegen möchten, reicht Ihnen möglicherweise die ursprüngliche Antwort.

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

Ursprüngliche Antwort

Wie in der Antwort von @ bobince geschrieben , wird diese Instanz nicht überschrieben , wenn in einem anderen Modul bereits ein Verweis auf dieses Modul vorhanden ist (insbesondere wenn es mit dem asSchlüsselwort like importiert wurde import numpy as np).

Dies erwies sich für mich als ziemlich problematisch, wenn ich Tests anwendete, die einen "Clean-Slate" -Status der Konfigurationsmodule erforderten. Daher habe ich eine Funktion mit dem Namen geschrieben reset_module, die importlibdie reloadFunktion verwendet und alle Attribute des deklarierten Moduls rekursiv überschreibt. Es wurde mit Python Version 3.6 getestet.

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

Hinweis: Vorsichtig verwenden! Die Verwendung dieser Module für nicht periphere Module (Module, die beispielsweise extern verwendete Klassen definieren) kann zu internen Problemen in Python führen (z. B. Probleme beim Beizen / Entbeizen).

EZLearner
quelle
1

Für mich im Fall von Abaqus ist es die Art und Weise, wie es funktioniert. Stellen Sie sich vor, Ihre Datei ist 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.
quelle
Diese Antwort ist eine direkte Kopie von hier: ebanshi.cc/questions/1942/…
SiHa
0

Ich hatte große Probleme beim Versuch, etwas in Sublime Text neu zu laden, aber schließlich konnte ich dieses Dienstprogramm schreiben, um Module in Sublime Text basierend auf dem Code neu zu laden sublime_plugin.py der zum Neuladen von Modulen verwendet wird.

Im Folgenden können Sie Module aus Pfaden mit Leerzeichen auf ihren Namen neu laden. Später nach dem Neuladen können Sie sie einfach wie gewohnt importieren.

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

Wenn Sie zum ersten Mal ausführen, sollte das Modul geladen werden. Wenn Sie jedoch später die Methode / Funktion erneut verwenden run_tests()können, werden die Testdateien neu geladen . Bei Sublime Text ( Python 3.3.6) passiert dies häufig, da der Interpreter nie geschlossen wird (es sei denn, Sie starten Sublime Text, dh den Python3.3Interpreter, neu).

Benutzer
quelle
-1

Eine andere Möglichkeit könnte darin bestehen, das Modul in eine Funktion zu importieren. Auf diese Weise wird nach Abschluss der Funktion des Moduls Müll gesammelt.

hackbot89
quelle
4
Das Modul wird niemals Müll gesammelt, da zumindest in eine globale Referenz gespeichert ist sys.modules.
Alle Arbeiter sind essentiell