2016-08-08 35 views
0

Betrachten Sie das einfache Beispiel:Python: Wie innere Ausnahme der Ausnahmekette zu fangen?

def f(): 
    try: 
     raise TypeError 
    except TypeError: 
     raise ValueError 

f() 

Ich möchte TypeError Objekt fangen, wenn ValueError nach f() Ausführung geworfen wird. Ist es möglich, es zu tun?

Wenn ich Funktion ausführen f() dann python3 Druck alle angehobenen Ausnahmen Ausnahmekette nach stderr (PEP-3134) wie

Traceback (most recent call last): 
    File "...", line 6, in f 
    raise TypeError 
TypeError 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "...", line 11, in <module> 
    f() 
    File "...", line 8, in f 
    raise ValueError 
ValueError 

So würde ich die Liste aller Ausnahmen Ausnahmekette erhält oder überprüfen, ob Ausnahme von ein Typ (TypeError im obigen Beispiel) existiert in der Ausnahmekette.

+0

Ich denke, es ist ein [XY Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Echte Frage: Was genau willst du hier erreichen (nicht _wie_ willst du das erreichen)? –

Antwort

6

Python 3 hat eine schöne syntaktische Verbesserung bei der Behandlung von Ausnahmen. Statt deutlich erhöht Valueerror, sollten Sie es von einer abgefangene Ausnahme erhöhen, d.h .:

try: 
    raise TypeError('Something awful has happened') 
except TypeError as e: 
    raise ValueError('There was a bad value') from e 

Beachten Sie den Unterschied zwischen den Tracebacks. Dieses verwendet raise from Version:

Traceback (most recent call last): 
    File "/home/user/tmp.py", line 2, in <module> 
    raise TypeError('Something awful has happened') 
TypeError: Something awful has happened 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
    File "/home/user/tmp.py", line 4, in <module> 
    raise ValueError('There was a bad value') from e 
ValueError: There was a bad value 

Obwohl das Ergebnis kann ähnlich scheinen in der Tat ist es eher anders! raise from speichert den Kontext der ursprünglichen Ausnahme und erlaubt es, alle Ausnahmen zurück zu verfolgen - was mit dem einfachen raise unmöglich ist.

die ursprüngliche Ausnahme zu erhalten, müssen Sie einfach __context__ neue Ausnahme des Attributs beziehen, das heißt

try: 
    try: 
     raise TypeError('Something awful has happened') 
    except TypeError as e: 
     raise ValueError('There was a bad value') from e 
except ValueError as e: 
    print(e.__context__) 
>>> Something awful has happened 

Hoffentlich ist die Lösung, die Sie gesucht haben.

Weitere Einzelheiten finden Sie PEP 3134 -- Exception Chaining and Embedded Tracebacks

+0

Danke. Um Ausnahme-Objekte von caught zu erhalten, muss 'ValueError as e' aufgerufen werden: 'e .__ cause__', das' TypeError'-Objekt zurückgibt. Wenn das 'TypeError'-Objekt (let' e2') ein cause-exception-Objekt hat, dann kann es durch 'e2 .__ cause__' usw. erhalten werden. Der Generator' def cause_gen (exc): yield exc; während exc .__ cause__: exc = exc .__ cause__; yield exc; 'gibt alle Exceptions der Exception-Kette zurück, in der das Argument init abgefangen wurde. – kupgov

+0

Also ist es unmöglich, Ausnahmen zu bekommen, wenn sie ohne 'von' ausgelöst wurden (unmöglich Quellcode zu bearbeiten)? – kupgov

+0

Leider nicht ohne dirty/hacky Code, der 'raise from' emuliert. Wenn Sie an Py2 gebunden sind, gibt es einen Backport in der * future * -Bibliothek. Im Wesentlichen wurde die PEP eingeführt, um die Unmöglichkeit, die inneren Ausnahmen zu bekommen, zu bewältigen. –