5 Stimmen

Wie kann man den Code einer Methode der Klasse Objekt in Python neu laden?

Ich bin einen Weg zu finden, um die Methode einer Klasse Objekt zur Laufzeit neu zu ladenHier ist das Beispiel: Ich habe zunächst eine Klasse A definiert, die in der Datei test.py liegt.

class A:
    def __init_(self):
        pass
    def Message(self):
        print "1"

dann starte ich die Python-Shell im Linux und führe den folgenden Code aus:

>>> from test import A
>>> a = A()
>>> a.Message()
1

Jetzt führe ich die test.py in der Fliege aus und ändere die Methode "Message":

class A:
    def __init_(self):
        pass
    def Message(self):
        print "2"

aber wenn ich die a.Message() in der Python-Shell ausführe, ist das Ergebnis immer die "1" und nicht "2"

Wie schreibe ich den Code, damit das Objekt "a.Message" den aktualisierten Code ausführt?

Herzlichen Dank!

chu

4voto

Sven Marnach Punkte 525472

Um Ihr Modul im interaktiven Interpreter zu relaodieren, können Sie

import test
reload(test)
from test import A

Dies hat jedoch keine Auswirkungen auf die Instanz von A die bereits vorhanden sind - sie werden noch vom alten Typ sein A daher die alte Methode. Ich denke, es ist nicht möglich, bestehende Instanzen zu ändern, und ich halte es auch nicht für eine gute Idee.

Übrigens würde ich empfehlen, die IPython für Code-Tests. Es erleichtert das rekursive Nachladen mit der %reload Magie, und (noch nützlicher) die %run Magie, um Module zu testen.

3voto

dan-man Punkte 2671

Ich habe gerade eine Weile damit verbracht, dieses Problem selbst zu lösen und bin zu einer etwas anderen Lösung gekommen als die, die hier vorgeschlagen wurde. Ich habe es in eine . mit vielen Kommentaren, aber wie es bei SO üblich ist, gebe ich hier eine kurze Erläuterung:

Anstatt einzelne Instanzen einer alten Version einer Klasse zu ändern oder sie in neue Instanzen der neuen Klasse zu kopieren, besteht die Idee darin, die Methoden der alten Klasse (d. h. die Attribute der Klasse selbst, nicht die Instanzen der Klasse) auf die aktualisierten Methoden der neuen Klasse zu setzen. Damit wird auch die Verkettung über mehrere Versionen der Klasse hinweg gewährleistet.

2voto

riccardo Punkte 63

Sie müssen Ihr Modul aus dem neuen Code neu laden, die Klasse abrufen und sie wieder der Instanz zuweisen:

import sys
def update_class(instance):
  cls=instance.__class__
  modname=cls.__module__
  del sys.modules[modname]
  module=__import__(modname)
  instance.__class__=getattr(module,cls.__name__)

Bei der Entwicklung und Aktualisierung des Codes können Sie denselben Trick anwenden, um Instanzen zu definieren, die ihre Klasse jedes Mal neu laden, wenn sie verwendet werden.

import sys

class ObjDebug(object):
  def __getattribute__(self,k):
    ga=object.__getattribute__
    sa=object.__setattr__
    cls=ga(self,'__class__')
    modname=cls.__module__ 
    mod=__import__(modname)
    del sys.modules[modname]
    reload(mod)
    sa(self,'__class__',getattr(mod,cls.__name__))
    return ga(self,k)

class A(ObjDebug):
   pass

a=A()

Wenn Sie den Code von A bearbeiten, um eine Methode hinzuzufügen, können Sie diese verwenden, ohne a erneut zu instanzieren.

Eigentlich del sys.modules[modname] scheint unangenehme Fehler zu verursachen, bei denen einige Symbole von einer Zeile zur anderen zu Keine Objekte werden. (nicht verstanden warum)

1voto

Blaze Punkte 1450

Die Frage formuliert ein leistungsfähiges Werkzeug, das ich häufig verwende, wenn ich neue Ideen zur Architektur und zu Algorithmen für Python entwickle und mit ihnen experimentiere und bestimmte Implementierungen nachladen möchte, ohne die aktuellen Locals zu stören.

Ich verwende einen vereinfachten Ansatz von

importlib.reload(my_module)
my_instance.my_method = types.MethodType(my_class.my_method, my_instance)

my_module wurde auf die Definition von Funktions- und Klassenimplementierungen reduziert. Für die wenigen Erstellung von globalen Werten auf Modulebene, die ich habe, schließe ich diese in anderen Modulen ein, damit sie beim Neuladen nicht überladen werden, da importlib.reload nur ein oberflächliches Neuladen durchführt.

Ich habe einige Dienstprogramme, die speziell auf meine Arbeitsweise zugeschnitten sind und die obige Technik nutzen, um das Nachladen von Modulen, Klassen und Funktionen, die ich aufliste, zu erleichtern.

Dieser Ansatz hilft mir, expliziter zu sehen, wie ich meine Laufzeitlogik ändere, wenn ich dies tue. iPython tut ähnliche Dinge und hat ähnliche Ziele wie die oben genannten, aber für meine Zwecke ist es zu magisch, aufgebläht und schlecht gestaltet, mit seiner API dünn dokumentiert. Es ist viel zu logisch mit Jupyter gekoppelt, und man hat das Gefühl, dass die API-Designer davon ausgehen, dass die API niemals außerhalb dieses Kontexts verwendet werden wird, so dass keine Anstrengungen für angemessene Abstraktionen unternommen wurden - eine sich selbst erfüllende Prophezeiung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X