Verhindern, dass Python die importierten Module zwischenspeichert

Lesezeit: 10 Minuten

Verhindern dass Python die importierten Module zwischenspeichert
Olivier Verdier

Bei der Entwicklung eines größeren Projekts (aufgeteilt in mehrere Dateien und Ordner) in Python mit IPython stoße ich auf die Probleme mit zwischengespeicherten importierten Modulen.

Das Problem ist die Anleitung import module liest das Modul nur einmal, auch wenn sich dieses Modul geändert hat! Jedes Mal, wenn ich etwas an meinem Paket ändere, muss ich IPython beenden und neu starten. Schmerzlich.

Gibt es eine Möglichkeit, das Neuladen einiger Module ordnungsgemäß zu erzwingen? Oder besser, um Python irgendwie daran zu hindern, sie zwischenzuspeichern?

Ich habe mehrere Ansätze ausprobiert, aber keiner funktioniert. Insbesondere stoße ich auf wirklich, wirklich seltsame Fehler, wie zum Beispiel einige Module oder Variablen, die auf mysteriöse Weise gleich werden None

Die einzige vernünftige Ressource, die ich gefunden habe, ist Python-Module neu laden, von pyunit, aber ich habe es nicht überprüft. Ich hätte gerne so etwas.

Eine gute Alternative wäre ein Neustart von IPython oder ein Neustart des Python-Interpreters.

Wenn Sie also in Python entwickeln, welche Lösung haben Sie für dieses Problem gefunden?

Bearbeiten

Um es klarzustellen: Ich verstehe natürlich, dass einige alte Variablen je nach vorherigem Zustand des Moduls bestehen bleiben können. Das ist okay für mich. Warum ist es in Python so schwierig, das erneute Laden eines Moduls zu erzwingen, ohne dass alle möglichen seltsamen Fehler auftreten?

Genauer gesagt, wenn ich mein gesamtes Modul in . habe eins Datei module.py dann funktioniert folgendes gut:

import sys
try:
    del sys.modules['module']
except AttributeError:
    pass
import module

obj = module.my_class()

Dieser Code funktioniert wunderbar und ich kann monatelang entwickeln, ohne IPython zu beenden.

jedoch, immer wenn mein Modul aus mehreren Submodulen besteht, bricht die Hölle los:

import os
for mod in ['module.submod1', 'module.submod2']:
    try:
        del sys.module[mod]
    except AttributeError:
        pass
# sometimes this works, sometimes not. WHY?

Warum ist das bei Python so unterschiedlich, ob ich mein Modul in einer großen Datei oder in mehreren Untermodulen habe? Warum sollte dieser Ansatz nicht funktionieren??

  • Dies ist eigentlich eine ziemlich beliebte Frage; jeden Monat auftauchen. Der derzeitige Konsens besteht darin, Ihren Dolmetscher neu zu starten, wie Mike betonte.

    – Xavier Ho

    27. Mai ’10 um 6:40

  • Erstens kann ich nicht verstehen, warum du dich unterdrückst Attributfehler. Es geht einfach nicht del sys.modules[mod] wird AttributeError auslösen… außer wenn du zurückprallst sys zu etwas anderem als dem eingebauten sys-Modul. Könnte es einfach sein, dass Sie im zweiten Code haben sys.module (die Wille raise AttributeError mit normalem sys) und im ersten hast du sys.modules? 😛

    – Veky

    4. August ’16 um 18:04

1641901566 27 Verhindern dass Python die importierten Module zwischenspeichert
Matt Anderson

import prüft, ob das Modul in ist sys.modules, und wenn ja, wird es zurückgegeben. Wenn Sie importieren möchten, dass das Modul frisch von der Festplatte geladen wird, können Sie den entsprechenden Schlüssel in . löschen sys.modules Erste.

Dort ist der reload eingebaute Funktion, die ein gegebenes Modulobjekt von der Festplatte neu lädt und in sys.modules. Bearbeiten — es wird den Code aus der Datei auf der Festplatte neu kompilieren und dann in den vorhandenen Modulen neu auswerten __dict__. Etwas möglicherweise ganz anderes, als ein neues Modulobjekt zu erstellen.

Mike Graham hat jedoch recht; Es ist schwierig, richtig neu zu laden, wenn Sie auch nur ein paar Live-Objekte haben, die auf den Inhalt des Moduls verweisen, das Sie nicht mehr haben möchten. Vorhandene Objekte referenzieren weiterhin die Klassen, aus denen sie instanziiert wurden, ist ein offensichtliches Problem, aber auch alle Referenzen, die mit Hilfe von . erstellt wurden from module import symbol zeigt immer noch auf ein beliebiges Objekt aus der alten Version des Moduls. Viele subtil falsche Dinge sind möglich.

Bearbeiten: Ich stimme dem Konsens zu, dass das Neustarten des Dolmetschers bei weitem das zuverlässigste ist. Aber zu Debugging-Zwecken könnten Sie etwas wie das Folgende versuchen. Ich bin mir sicher, dass es Eckfälle gibt, für die dies nicht funktionieren würde, aber wenn Sie nichts zu verrücktes (sonst) mit dem Laden von Modulen machen deine Paket, es könnte nützlich sein.

def reload_package(root_module):
    package_name = root_module.__name__

    # get a reference to each loaded module
    loaded_package_modules = dict([
        (key, value) for key, value in sys.modules.items() 
        if key.startswith(package_name) and isinstance(value, types.ModuleType)])

    # delete references to these loaded modules from sys.modules
    for key in loaded_package_modules:
        del sys.modules[key]

    # load each of the modules again; 
    # make old modules share state with new modules
    for key in loaded_package_modules:
        print 'loading %s' % key
        newmodule = __import__(key)
        oldmodule = loaded_package_modules[key]
        oldmodule.__dict__.clear()
        oldmodule.__dict__.update(newmodule.__dict__)

Was ich ganz kurz so getestet habe:

import email, email.mime, email.mime.application
reload_package(email)

Drucken:

reloading email.iterators
reloading email.mime
reloading email.quoprimime
reloading email.encoders
reloading email.errors
reloading email
reloading email.charset
reloading email.mime.application
reloading email._parseaddr
reloading email.utils
reloading email.mime.base
reloading email.message
reloading email.mime.nonmultipart
reloading email.base64mime

  • Ich habe diese Ansätze ausprobiert, indem ich den entsprechenden Eintrag in gelöscht habe sys.modules, und mit reload. Es funktioniert gelegentlich, erzeugt aber manchmal sehr, sehr subtile und seltsame Fehler, bei denen einige Variablen plötzlich zu werden None ohne ersichtlichen Grund.

    – Olivier Verdier

    27. Mai ’10 um 6:30

  • “Herr Doktor, es tut weh, wenn ich so gehe”, “Nun, tun Sie das nicht”. hab ich mir immer angeschaut reload als reine Erleichterung beim Debuggen und halten es für einen Dokumentationsfehler, dass es für das tatsächliche Laden von Live-Daten vorgeschrieben ist, da die semantischen Fehler, die es mit sich bringt, schwerwiegend sein können.

    – msw

    27. Mai ’10 um 6:45

  • ich fand die del sys.modules[key] Zeile Ihrer Antwort, die für mein Szenario nützlich ist. Ich stimme zu, dass dies das Caching wie in der Frage gestellt nicht verhindert, aber diese Funktionen könnten einem helfen, ein Verhalten wie das regelmäßige Ablaufen des Python-Cache aufzubauen.

    – Daniel D.

    6. Mai ’17 um 11:48

Das Beenden und Neustarten des Dolmetschers ist die beste Lösung. Jede Art von Live-Neulade- oder No-Caching-Strategie wird nicht reibungslos funktionieren, da Objekte aus nicht mehr vorhandenen Modulen existieren können und weil Module manchmal den Status speichern und weil selbst wenn Ihr Anwendungsfall Hot-Reloading wirklich zulässt, es zu kompliziert ist, darüber nachzudenken es wert sein.

  • Aberglaube! Auch in solchen allgemeinen Fällen wie in PyUnit, aber im Einzelfall dauert die Einrichtung nicht lange und zahlt sich sehr gut aus. In meinem Schema gibt es beispielsweise ein leichtgewichtiges Hauptmodul, das ein Singleton enthält, an dem alle meine anderen Instanzen hängen und das nur ihre Methoden, keine Funktionen aufruft. Nachladen ist von for each i: del sys.modules[mymodule_i], reload(..)-ing sie, dann tausche die __class__ jeder Instanz von alt nach neu.

    – Evgeni Sergeev

    1. November ’15 um 12:25

  • Debugging, verständlicher Code ist schlicht und einfach. Eine solche Erhöhung der Komplexität ist weder sinnvoll noch sinnvoll. Ich empfehle nicht, etwas aus der Ferne so glatt wie dieses zu machen.

    – Mike Graham

    2. November ’15 um 15:27

  • Außer vielleicht, wenn die Zielumgebung nicht so einfach neu gestartet werden kann. Blender erfordert beispielsweise einen Anwendungsneustart, um den Interpreterstatus zu löschen, was eine schreckliche Benutzererfahrung für Add-Ons ist, die ein- und ausgeschaltet werden (die Add-On-Benutzeroberfläche ermöglicht dies), wenn das Add-On größer als ein Modul ist.

    – Coburn

    23. Okt ’17 um 5:27

Verhindern dass Python die importierten Module zwischenspeichert
ojdo

Mit IPython kommt das Autoreload-Erweiterung das vor jedem Funktionsaufruf automatisch einen Import wiederholt. Es funktioniert zumindest in einfachen Fällen, aber verlassen Sie sich nicht zu sehr darauf: Nach meiner Erfahrung ist immer noch ein Neustart des Interpreters von Zeit zu Zeit erforderlich, insbesondere wenn Codeänderungen nur an indirekt importiertem Code erfolgen.

Anwendungsbeispiel von der verlinkten Seite:

In [1]: %load_ext autoreload

In [2]: %autoreload 2

In [3]: from foo import some_function

In [4]: some_function()
Out[4]: 42

In [5]: # open foo.py in an editor and change some_function to return 43

In [6]: some_function()
Out[6]: 43

  • Ich habe das gefunden, während %autoreload 2 funktioniert nicht, wenn es tiefe Hierarchien gibt, diese Lösung funktioniert immer:stackoverflow.com/a/13096672/311567 was hoffentlich die Standardeinstellung in ipython wird

    – schneidig

    3. September ’14 um 19:31

Verhindern dass Python die importierten Module zwischenspeichert
Mitendra

Für Python-Version 3.4 und höher

import importlib 
importlib.reload(<package_name>) 
from <package_name> import <method_name>

Siehe unten Dokumentation für Details.

Es gibt hier bereits einige wirklich gute Antworten, aber es lohnt sich, Dreload zu kennen, eine in IPython verfügbare Funktion, die als “Deep Reload” funktioniert. Aus der Dokumentation:

Das Modul IPython.lib.deepreload ermöglicht es Ihnen, ein Modul rekursiv neu zu laden: Änderungen, die an seinen Abhängigkeiten vorgenommen wurden, werden neu geladen, ohne dass es beendet werden muss. Um es zu verwenden, gehen Sie wie folgt vor:

http://ipython.org/ipython-doc/dev/interactive/reference.html#dreload

Es ist als “globales” im IPython-Notebook verfügbar (zumindest meine Version, auf der v2.0 ausgeführt wird).

HTH

1641901566 302 Verhindern dass Python die importierten Module zwischenspeichert
toriningen

Sie können die in beschriebenen Importhakenmaschinen verwenden PEP 302 um nicht Module selbst zu laden, sondern eine Art Proxy-Objekt, das es Ihnen ermöglicht, mit dem zugrunde liegenden Modulobjekt alles zu tun, was Sie wollen – neu laden, Referenz darauf löschen usw.

Ein zusätzlicher Vorteil besteht darin, dass Ihr aktuell vorhandener Code keine Änderung erfordert und diese zusätzliche Modulfunktionalität von einer einzigen Stelle im Code entfernt werden kann – wo Sie tatsächlich den Finder hinzufügen sys.meta_path.

Einige Gedanken zur Implementierung: Erstellen Sie einen Finder, der zustimmt, jedes Modul außer eingebauten zu finden (Sie haben nichts mit eingebauten Modulen zu tun), dann erstellen Sie einen Lader, der ein Proxy-Objekt zurückgibt, das eine Unterklasse von . ist types.ModuleType anstelle eines echten Modulobjekts. Beachten Sie, dass Loader-Objekte nicht gezwungen sind, explizite Verweise auf geladene Module in zu erstellen sys.modules, aber es wird dringend empfohlen, da es, wie Sie bereits gesehen haben, unerwartet fehlschlagen kann. Proxy-Objekt sollte alle abfangen und weiterleiten __getattr__, __setattr__ und __delattr__ auf das zugrunde liegende reale Modul, auf das es verweist. Sie müssen wahrscheinlich nicht definieren __getattribute__ weil Sie mit Ihren Proxy-Methoden keine echten Modulinhalte verbergen würden. Jetzt sollten Sie also auf irgendeine Weise mit dem Proxy kommunizieren – Sie können eine spezielle Methode zum Löschen der zugrunde liegenden Referenz erstellen, dann das Modul importieren, die Referenz aus dem zurückgegebenen Proxy extrahieren, den Proxy löschen und die Referenz auf das neu geladene Modul halten. Puh, sieht beängstigend aus, sollte aber dein Problem beheben, ohne Python jedes Mal neu zu laden.

1641901566 541 Verhindern dass Python die importierten Module zwischenspeichert
Benutzer7175781

Ich verwende PythonNet in meinem Projekt. Glücklicherweise habe ich einen Befehl gefunden, der dieses Problem perfekt lösen kann.

using (Py.GIL())
        {
            dynamic mod = Py.Import(this.moduleName);
            if (mod == null)
                throw new Exception( string.Format("Cannot find module {0}. Python script may not be complied successfully or module name is illegal.", this.moduleName));

            // This command works perfect for me!
            PythonEngine.ReloadModule(mod);

            dynamic instance = mod.ClassName();

  • Ich glaube, die Frage betrifft den Neustart des Python-Interpreters. Sie scheinen C# und Python-Engine darin zu verwenden. ? Wahrscheinlich nicht das, was das OP sucht.

    – Vasif

    18. November ’16 um 1:04

  • @ user7175781 Die Syntax funktioniert auf meinem System nicht, egal was ich versuche. Ich denke, PythonNet hat eine andere Syntax und API als ipython. Ich hatte gehofft, Ihr Beispiel zum Laufen zu bringen, aber nach vielen vom Interpreter gemeldeten Fehlern wurde mir endlich klar, dass Sie PythonNet-Sprache gesagt haben.

    – Geoffrey Anderson

    21. Januar ’17 um 17:36

.

354540cookie-checkVerhindern, dass Python die importierten Module zwischenspeichert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy