Wie bekomme ich einen Verweis auf eine Instanzmethode von einem Dekorateur

Ich habe eine GUI-Bibliothek verwendet, mit der Sie Signale an Signalhandler mit einer Verbindungsfunktion anschließen können, zum Beispiel:

widget.connect(signal, callback) 

Bedeutet, dass der Funktionsrückruf ausgeführt wird, wenn das Signal aus dem Widget abgefeuert wird. In einem Versuch, meinen Code schöner zu machen und eine Reihe von Anrufen von meinem Konstruktor zu entfernen, entschied ich mich, einen Dekorateur zu benutzen, der gut funktioniert:

 def callback(widget, signal) def decorate(f): widget.connect(signal, f) return f return decorate ... @callback(widget, signal) def do_something(): ... 

Das funktioniert hervorragend, bis ich das in einer Klasse machen musste – die Funktion ist dekoriert, bevor es an die Klasse gebunden ist, was bedeutet, dass die Callback-Funktion nicht die Instanz der Klasse erhält, die es besitzt und es nutzlos macht. Gibt es einen Weg, um das zu arbeiten?

One Solution collect form web for “Wie bekomme ich einen Verweis auf eine Instanzmethode von einem Dekorateur”

Eine relativ einfache Lösung hierfür ist möglich. Wir beginnen mit dem Dekorator, um die Funktion zu markieren. Wenn Instanzen aufgebaut sind, suchen wir nach diesen Markierungen und registrieren die Rückrufe.

Genauer gesagt arbeitet das Mark- und Recapture-Muster, indem er den Dekorator verwendet, um die Funktion zu markieren, bevor er gebunden ist, und dann finden sie ihn unter den gebundenen Methoden der Instanz im Konstruktor.

Zuerst verwenden wir einen Dekorator, um die Markierung zu machen (wir verwenden einen Satz, um mehrere Markierungen auf einer Methode zu erlauben):

 def callback(*args): def decorate(f): try: f._marks.add(args) except AttributeError: f._marks = {args} return f return decorate 

Dann verwenden wir das Inspektionsmodul , um die gebundenen Versionen der markierten Funktionen zu finden und diese zu verbinden:

 def connect_callbacks(obj): for _, f in inspect.getmembers(obj, inspect.ismethod): try: marks = f.__func__._marks except AttributeError: continue for widget, signal in marks: widget.connect(signal, f) 

__func__ ist der Name der ursprünglichen, ungebundenen Funktion. So können wir auf die von uns angewandten Marken zugreifen und unsere Rückeroberung erleichtern.

Wir können dann einfach unsere Klasse erstellen und unsere Funktionen verzieren und uns daran erinnern, unsere Rückrufe im Konstruktor zu verbinden:

 class Test: def __init__(self): ... connect_callbacks(self) @callback(widget, signal) def test(): ... 

Dies ermöglicht es uns, die gebundenen Methoden mit einem Dekorateur zu verbinden.

Edit: Ich habe eine kleine Bibliothek auf Github veröffentlicht, die das für dich tut – es heißt Rekap .

  • Wie kann ich verhindern, dass Vorrichtungen mit django post_save Signalcode in Konflikt stehen?
  • Signalbehandlung in Python
  • Django: Signal, wenn Benutzer sich anmeldet?
  • Python schließen Kinder beim Schließen des Hauptprozesses
  • Python ist die beste Programmiersprache der Welt.