2016-08-08 13 views
0

Neu bei Python und ich habe eine Reihe von Funktionen, um verschiedene Aufgaben auf etwas Hardware durchzuführen. Jede Funktion hat unterschiedliche Anzahlen von Parametern und gibt zurück.Ausnahmebehandlung in Decorator-Funktion

Ich möchte eine Art generische "wiederholen" Wrapper-Funktion, die eine Ausnahme von jeder meiner Funktionen abfangen und einige Fehlerbehandlung (wie das Wiederholen der Aufgabe).

Von was ich verstehe, sollte ich in der Lage sein, eine Decorator-Funktion als generische Wrapper für jede meiner Funktionen zu verwenden. Das scheint zu funktionieren, aber ich bin anscheinend nicht in der Lage, irgendeine Ausnahme von der aufgerufenen Funktion von meiner Decorator-Funktion zu bekommen.

Ich habe an verschiedenen Beispielen sah und kommen mit dieser:

def retry(function): 
    def _retry(*args, **kwargs): 
     try: 
      reply = function(*args, **kwargs) 
      print "reply: ", reply 
      return reply 
     except PDError as msg: 
      print "_retry", msg 
     except: 
      print "_retry: another error" 
    return _retry 

Dann rufe ich ihm den Namen einer meiner Funktionen:

value = retry(pd.command_get_parameter(0x00)) 

Es scheint, meine Funktion aufzurufen und korrekt zurückgeben, aber die Ausnahmen werden nie innerhalb meiner Wiederholungsfunktion abgefangen. So kann ich einen Fehler nicht behandeln und eine Wiederholung versuchen.

Ich habe dies auch versucht:

from functools import wraps 

def retry(function): 
    @wraps(function) 
    def _retry(*args, **kwargs): 
    ..... 

Ich bin nicht sicher, was ich falsch mache, oder ob dies auch der beste Weg, dies zu tun. Hat jemand einen Vorschlag, wie man das macht? Ich möchte nicht wirklich separate "Wiederholungs" -Funktionen für jede meiner Hauptfunktionen machen müssen.

+2

Meinten Sie 'Wiederholungs (pd.command_get_parameter) (0x00)'? Im Moment übergeben Sie das Ergebnis von 'pd.command_get_parameter (0x00)' an 'retry' als' function'. – Ryan

+0

@Will: Sie sollten wie folgt verwenden: '@retry def command_get_parameter (..)'. Sie können auch eine Funktion wie 'retry (command_get_parameter)' übergeben und stattdessen die zurückgegebene Funktion verwenden. Du machst keinen von beiden. Sie übergeben den zurückgegebenen Wert von 'command_get_parameter (..)', um es erneut zu versuchen - wo Sie eine Funktion übergeben sollten. – SuperSaiyan

+0

@Ryan: Danke. Jetzt, wo du es erklärt hast, kann ich sehen, warum es nicht funktioniert hat, weil ich das Ergebnis weitergegeben habe. – Will

Antwort

0

mein Kommentar Konvertieren zu beantworten:

def retry(function): 
    @wraps(function) 
    def _retry(*args, **kwargs): 
     try: 
      reply = function(*args, **kwargs) 
      print "reply: ", reply 
      return reply 
     except PDError as msg: 
      print "_retry", msg 
     except: 
      print "_retry: another error" 
    return _retry 

class SomeClass(object): 

    @retry 
    def command_get_parameter(..): 
     return <some value> 
s = SomeClass() 
result = s.command_get_parameter(..) #retry(..) actually invokes this function. 

Dekorateure in einer Funktion übernehmen, und gibt eine Funktion eingerichtet:

Sie mögen verwenden sollten. Eine Dekoration ist etwas, das etwas tun kann, bevor die Funktion aufgerufen wird, danach, oder Ausnahmen abfangen usw. Wenn Sie die obige Syntax (@retry), der Interpreter retry(..) aufrufen, übergibt das Funktionsobjekt (command_get_parameter), und ersetzt die . Funktion mit der von retry(command_get_parameter) zurück Funktion

Was ist hier los ist etwas ähnlich wie unter den Schritten (Pseudo-Code):

new_command_get_parameter = retry(command_get_parameter) #@retry has this effect. 
result = new_command_get_parameter(your_input) 

die Differenz wird die beiden oben genannten Schritte für Sie durch den Interpreter getan magisch sind fertig - Halten Sie den Code sauberer und lesbar für die Augen.


Derzeit Aufruf Sie die Funktion und das Bestehen der Folge davon zu retry(..) was offensichtlich falsch ist. Außerdem werden Ausnahmen nicht so behandelt, wie Sie es möchten.


aktualisieren: Wenn Sie die Wiederholung wollen die Instanz-Variable für den Zugriff auf alles, was Sie tun müssen, ist _retry den ersten Parameter als self verwenden zu lassen.Etwas wie:

def retry(func): 
    def _retry(self, *args, **kwargs): 
     print "Decorator printing a:", self.a 
     print "Decorator printing b:", self.b 
     try: 
      return func(*args, **kwargs) 
     except Exception as e: 
      print "Caught exception" 
      return "Grr.." 
    return _retry 


class Temp(object): 
    def __init__(self, a, b): 
     self.a = a 
     self.b = b 

    @retry 
    def command(self, *args, **kwargs): 
     print "In command." 
     print "Args:", args 
     print "KWargs:", kwargs 

     raise Exception("DIE!") 

t = Temp(3, 5) 

print t.command(3,4,5, a=4, b=8) 

Ausgang:

Decorator printing a: 3 
Decorator printing b: 5 
In command. 
Args: (4, 5) 
KWargs: {'a': 4, 'b': 8} 
Caught exception 
Grr.. 
+0

Danke für die Antwort. Also, wenn ich "Wiederholung" Teil der "SomeClass" in Ihrem Beispiel machen sollte, wie definiere ich es? Zum Beispiel: Klasse Someclass (Objekt): @retry def wiederholen (self, Funktion): Versuch: Antwort = function (* args, ** kwargs) Antwort Rückkehr Ausnahme: #handle Fehler Benötige ich @Wraps (Funktion) – Will

+0

@Will: Aktualisiert meine Antwort .. – SuperSaiyan

+0

Ich glaube nicht, dass ich auf meine letzte Frage klar war. Ist es möglich, die Wiederholungsfunktion Teil der SomeClass-Klasse zu machen? Zum Beispiel würde ich das benötigen, wenn ich als Teil des Wiederholungsmechanismus eine andere Funktion in SomeClass aufrufen müsste. Hier ist, was ich versucht, aber es ist nicht gültig: 'code' Klasse Someclass (Objekt): def wiederholen (self, Funktion): @wraps (Funktion) def _retry (* args, * * kwargs): versuchen: Antwort = Funktion (* Args, ** Kwargs) – Will