Exception wird nicht abgefangen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

Hallo,

ich habe eine simple Methode entwickelt, die eine andere Methode in eine While-Schleife mit try-except Block durchführt. Das ist eigentlich für bestimmte Methoden gedacht, die manchmal eine Exception zurückgeben. Aber wenn man diese Exception abfangt und die Methode wieder auruft, kann die Methode erfolgreich durchgefürt werden. Die Methode sieht wie folgt aus:

Code: Alles auswählen

def CallWithExceptionHandler(self, Function, Expected_Value):
        
        Starttime = time.time()
        while time.time() - Starttime < 20:
            try:
                Function
                if Function == Expected_Value:
                    return Function
            except Exception, e:
                message = str(e)
        else:
            if message != " ":
                print message
                return False
            else:
                return False
das heist wenn ich hier die Methode "function" aurufen möchte sieht es wie folgt aus:

Code: Alles auswählen

self.CallWithExceptionHandler(function, Expected_Value)
das Problem hier ist, dass der Exception nicht abgefangen wird und wird before die While-Schleife endet zurückgegeben.
weiss vielleicht jemand wo der Fehler bei mir liegt?

danke
BlackJack

@zizou2981: Der Code macht keinen Sinn und ist sicher nicht der den Du tatsächlich ausführst. Einmal steht da ein unsinniges `Function` was keinerlei Effekt hat, und dann vergleichst Du `Function` mit `Expected_Value` um, wenn die gleich sind, `Function` zurück zu geben. Häh? Wenn die Vergleichsoperation hier nicht völlig pervers implementiert ist, dann ist das total sinnbefreit einen solchen Vergleich in eine Schleife mit Zeitüberschreitung zu stecken, weil da immer das gleiche heraus kommen wird bei dem Vergleich.

Da innerhalb der ``while``-Schleife kein ``break`` vorkommt, glaube ich nicht, dass Du die Semantik des ``else``-Zweiges zu Schleifen verstanden hast.

Mal angenommen der wird ausgeführt und es gab keine Ausnahme in dem Code davor, was glaubst Du welcher Wert dann an `message` gebunden ist!?
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

@Black
ein return tut hier das gleiche wie break. Funktion steht als Beispiel für eine richtige Funktion, die etwas zurück gibt. Das was zurückgegeben wird, wird dann mit Expected_Value vergliechen. mit message hast du Recht, denn da hat was gefählt:

Code: Alles auswählen

def CallWithExceptionHandler(self, Function, Expected_Value):
        
        message = ""
        Starttime = time.time()
        while time.time() - Starttime < 20:
            try:
                Function
                if Function == Expected_Value:
                    return Function
            except Exception, e:
                message = str(e)
        else:
            if message != " ":
                print message
                return False
            else:
                return False
Die Methoden, die ich hier aufrufe, werden über CORBA aufgerufen. Manchmal gibt CORBA ein Exception zurück, aber wenn ich die Exception abfange und das Aufrufen wiederhole, kann das problem behoben werden, deswegen habe ich diese Methode entwickelt. hier ist ein bessere Beispiel:

Code: Alles auswählen

self.__Telephony.changeCallEntryStatus(IndexCallEntry, telNumber, Telephony.CST_ACTIVE)
=> das ist eine Methode, die ich über CORBA aufrufe. statt jedes mal while und try-except beim aufrufen zu geben, habe ich die Methode "CallWithExceptionHandler" entwickelt, dann kann die CORBA-Methode so aufrufen:

Code: Alles auswählen

self.CallWithExceptionHandler(self.__Telephony.changeCallEntryStatus(IndexCallEntry, telNumber, Telephony.CST_ACTIVE), Telephony.CST_ACTIVE)
der Exception wird hier aber nicht abgefangen.
ich habe auch vergessen zu erwähnen, dass wenn ich die CORBA-Methode so aufrufe, dann funktioniert:

Code: Alles auswählen

message = ""
Starttime = time.time()
while time.time() - Starttime < 25:
        try:
             result = self.__Telephony.changeCallEntryStatus(IndexCallEntry, telNumber, Telephony.CST_ACTIVE)
             if result == Telephony.CST_ACTIVE:
                   break
         except Exception, e:
                   message = str(e)
else:
       if message != ""
             print message
             return False
BlackJack

@zizou2981: ``return`` tut nicht das gleiche wie ``break``, denn ``return`` beendet die Funktion, wird kein Code nach der Schleife mehr ausgeführt, egal ob er in einem ``else``-Zeig steht oder nicht. Es ist also sinnfrei den Code in einen ``else``-Zweig zu stecken. Das ``else`` bewirkt nichts, ausser den Code komplizierter erscheinen zu lassen, als er tatsächlich ist.

Ebenfalls unnötig kompliziert ist das ``if``/``else`` wo in beiden Zweigen ein ``return False`` am Ende steht, und der ``else``-Zweig nur daraus besteht. Das kann man kürzer und ohne das ``else`` formulieren.

Der Rückgabewert der Funktion ist auch eigenartig bis unsinnig. Sie gibt entweder den `Expected_Value` zurück, den man ja schon vor dem Aufruf kennt, oder `False`. Sollte `Expected_Value` allerdings `False` sein, kann man das nicht mehr vom `Expected_Value` unterscheiden. Unter anderem diese Schwierigkeit ist ein Grund warum man Ausnahmen eingeführt hat. Die sollte man statt "Fehlerwerten" auch verwenden. Zumal ich mir vorstellen könnte, dass ein Aufrufer auch ganz gerne wüsste *warum* der Aufruf fehlgeschlagen ist.

Ich nenne das übrigens Funktion weil es eine ist. Und damit sollte man das auch nicht auf einer Klasse definieren, oder zumindest das `self` weglassen und es explizit zu einer `staticmethod()` machen.

Da Du wiederholt nicht zeigst wie der Code *tatsächlich* aussieht, überleg Dir doch mal nur so als Gedankenspiel was passiert wenn in dem Quelltext innerhalb des ``try``-Blocks ein Tippfehler in einem Namen ist. Wie würdest Du das bemerken!? Wobei ich jetzt mal davon ausgehe, dass Du `message` nach der Schleife nicht wirklich mit einem Leerzeichen vergleichst, sondern mit der leeren Zeichenkette.

Statt dem doppelten Unterstrich bei `__Telephony` würde auch einer genügen. Es sei denn Du verwendest hier tatsächlich Mehrfachvererbung und hättest Sorge wegen einer eventuellen Namenskollision.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

zizou2981 hat geschrieben:

Code: Alles auswählen

[...]
                Function
                if Function == Expected_Value:
                    return Function
[...]
Das sieht hochgradig merkwürdig aus. Nach dem, was du im Freitext beschrieben hast, sollte das doch eher so etwas sein:

Code: Alles auswählen

[...]
                result = Function()
                if result == Expected_Value:
                    return result
[...]
Ich bin allerdings mit dem gesamten Code nicht glücklich. BlackJack hat die Gründe dafür ja bereits genannt.
Bobby-John-Joe
User
Beiträge: 7
Registriert: Freitag 23. September 2011, 19:50

Code: Alles auswählen

self.CallWithExceptionHandler(self.__Telephony.changeCallEntryStatus(IndexCallEntry, telNumber, Telephony.CST_ACTIVE), Telephony.CST_ACTIVE)
Hier wird nichts abgfangen von deinem Code, weil du gar nicht bis in deine Funktion kommst (falls ein Fehler auftritt in obiger Funktion). Du übergibst nicht die Funktion

Code: Alles auswählen

self.__Telephony.changeCallEntryStatus(IndexCallEntry, telNumber, Telephony.CST_ACTIVE)
sondern deren Rückgabewert.
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

Ok ich versuche jetzt die Frage einfacher zu stellen: ich möchte gern wissen, ob ein abfangen einer Exception in einer Funktionshierarchie möglich ist?
hier ist ein einfache Beispiel:

Code: Alles auswählen

def funktion3(): 
    raise TypeError

def funktion2(): 
      result = funktion3()
      if result = true:
         return True
      else:
         return False
def funktion1(): 
   message = ""
   starttime = time.time()
   while time.time()- starttime < 10:
           try: 
                result = funktion2() 
                if result = true:
                   break
           except TypeError, e:  
                message = str(e)
                continue
   else:
          print message
deets

Bitte poste code, der auch laeuft.

Code: Alles auswählen

if result = true:
enthaelt gleich 2 Fehler in einem Ausdruck und zeigt, dass dein code niemals gelaufen ist!

Und was deine eigentliche Frage angeht: natuerlich kann man exceptions ueber mehrere Funktionsaufrufe fangen.
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

ok das Problem habe ich jetzt gelöst. Danke für die Hilfe. mein Fehler war, dass ish immer die komplette Funktion als Parameter zu andere funktion gegeben habe.
danke :)
BlackJack

@zizou2981: Nein Du hast eben *nicht* die Funktion übergeben, sondern deren *Rückgabewert*. Das hat Bobby-John-Joe weiter oben doch schon bemerkt.
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

genau so war es :oops:

Danke an alle :)
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

nur als Hilfe für Kollegen, dei das gleiche Problem hatten, man kann das Problem so lösen (Beispiel):

Code: Alles auswählen

def function3(x, y):
    c = x - y
    return c

def function2(x, y):
    result = function3(x, y)
    return result

def function1(function, expected_value, *arg):
    message = ""
    starttime = time.time()
    while time.time() - starttime < 3:
            try:
                    result = function(*arg)
                    if result == expected_value:
                            break
            except Exception, e:
                    message = str(e)
    else:
            if message != "":
                    print message
                    return False
            else:
                    print result
                    return False
    return result
beim Aufruf der Methode function2 sieht es dann so aus. Im Fehlerfall wird das Ergebnis erst nach dem Durchlauf der Schleife zurückgegeben (nach 3 Sekunden):

Code: Alles auswählen

>>> function1(function2, 5, 8, 3)
5
>>> function1(function2, 5, 8, 5)
3
False
>>> function1(function2, 5, 8, "a")
unsupported operand type(s) for -: 'int' and 'str'
False
=> Es gibt bestimmt andere Lösungen. das ist nur ein Vorschlag

Danke nochmal für die Hilfe :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Da passt es ja gleich an allen Ecken und Enden nicht:
- Auch wenn function3 und function2 nur Beispiele sind, das Binden der Ergebnisse an ``c`` und ``result`` kann man sich hier sparen und die Werte sofort zurückgeben.
- ``message`` sollte nicht mit einem leeren String initialisiert werden, sondern mit None. Dazu ist es gedacht.
- Dein "3 Sekunden warten" - warum auch immer man so etwas machen möchte - macht etwas ganz anderes als du wahrscheinlich glaubst. Es wird nicht drei Sekunden lang gewartet, was man mit ``time.sleep`` realisieren würden, sondern verbrät drei Sekunden lang die volle Rechenzeit eines Kerns, nur um den Block immer und immer wieder auszuführen. Zumindest im Fall einer Exception oder eines falschen Ergebnis. Die ganze Schleife an sich ist überflüssig.
- Das ``str(e)`` ist überflüssig.
- Den ganzen else-Block der while-Schleife kann man sich sparen, wenn die Ausgaben dort gemacht werden, wo die Ergebnisse entstehen. Der Erfolgsfall kann statt des ``break``s ausgegeben werden und der Fehler beim Abfangen der Ausnahme.
- Das die beiden ``return False`` hier doppelt sind, sollte eigentlich auf den ersten Blick auffallen. Etwas, was sowohl im if-Block, als auch im else-Block, ausgeführt wird, sollte außerhalb der Blöcke stehen.
- Auch ist der Rückgabewert ``False`` an sich verkehrt. Es ist ein seltsamen Verhalten, wenn in einem Fall False geliefert wird, in einem anderen das Ergebnis einer Funktion. Und was passiert, wenn eine Funktion von sich aus False liefert? Wie willst du dann unterscheiden, ob eine Berechnung fehlerhaft war oder ob das Ergebnis korrekt ist?
- mittels ``Exception`` alle Fehlermeldungen abzufangen ist recht großzügig und kann sehr leicht zu ungewolltem Verhalten führen. Da es aber wie eine Testfunktion aussieht, scheint so verhalten so gewünscht zu sein. Ich würde allerdings noch einen Parameter einführen, mit dem angegeben werden kann, welche Exceptions abgefangen werden sollen.
- Das Testen bringt mich bereits auf den letzten Punkt: Python besitzt bereits Module für Unittests, suchst du vielleicht so etwas?

Sebastian
Das Leben ist wie ein Tennisball.
Benutzeravatar
zizou2981
User
Beiträge: 59
Registriert: Donnerstag 23. Juni 2011, 21:46

@EyDu: warum ich sowas brauche habe ich vorher erwähnt. einfach lesen.
es geht hier nict um Python exception, sondern CORBA-Exception :)
BlackJack

@zizou2981: Viele von den Punkten habe ich weiter oben auch schon einmal angemerkt. Und natürlich geht es hier Python-Ausnahmen. Eben *alles* was von `Exception` abgeleitet ist. Das schliesst neben den Python-Ausnahmen von der verwendeten CORBA-Bibliothek natürlich auch *alle* anderen Ausnahmen ein.
Antworten