5 Stimmen

Auffangen von nicht behebbaren Ausnahmen und erneutes Auslösen

Dies ist eine Folgefrage zu meiner Frage Hängen in Python-Skript mit SQLAlchemy und Multiprocessing . Wie in dieser Frage erörtert, ist das Ablegen von Ausnahmen in Python problematisch. Dies ist normalerweise kein Problem, aber ein Fall, in dem dies der Fall ist, ist, wenn Fehler im Python-Multiprocessing-Modul auftreten. Da Multiprocessing Objekte durch Picking verschiebt, kann ein Fehler innerhalb eines Multiprocessing-Prozesses dazu führen, dass der gesamte Prozess hängen bleibt, wie in dieser Frage gezeigt wurde.

Ein möglicher Ansatz besteht darin, alle problematischen Ausnahmen zu beheben, wie in dieser Frage beschrieben. Dies ist nicht einfach, da man nicht ohne weiteres im Voraus wissen kann, welche Ausnahmen aufgerufen werden können. Ein alternativer Ansatz, der in der vorgeschlagen von lbolla in einer Antwort auf die Frage ist es, die Ausnahme abzufangen, eine gleichwertige harmlose Ausnahme zu konstruieren und dann erneut auszulösen. Ich bin mir jedoch nicht sicher, wie ich das genau machen soll. Betrachten Sie den folgenden Code.

class BadExc(Exception):
    def __init__(self, message, a):
        '''Non-optional param in the constructor.'''
        Exception.__init__(self, message)
        self.a = a

import sys
try:
    try:
        #print foo
        raise BadExc("bad exception error message", "a")
    except Exception, e:
        raise Exception(e.__class__.__name__ + ": " +str(e)), None, sys.exc_info()[2]
except Exception, f:
    pass

import cPickle
a = cPickle.dumps(f)
l = cPickle.loads(a)
print "raising error"
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Dieser Code markiert und entmarkiert die Ausnahme, löst sie aus und gibt den Fehler

raising error
Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
Exception: BadExc: bad exception error message

Kredite an Glenn Maynards Antwort auf ""Inner exception" (with traceback) in Python?" . Dies hat die wichtigen Dinge, nämlich den Traceback, die Fehlermeldung und den Ausnahmetyp, so dass dies vielleicht das Beste ist, was man tun kann. Aber idealerweise möchte ich etwas, das genau wie die ursprüngliche Ausnahme aussieht, nämlich

Traceback (most recent call last):
  File "<stdin>", line 11, in <module>
__main__.BadExc: bad exception error message

oder allgemeiner, mit dem Namen der Ausnahme im Vordergrund, anstatt Exception . Ist dies möglich?

Alternativ kann anstelle der BadExc Klasse, kann man die print foo Anweisung, die eine NameError . Diese Ausnahme erfordert jedoch keine besondere Behandlung.

2voto

Rob Wouters Punkte 14969

Sie können überschreiben sys.excepthook um zu erreichen, was Sie wollen. Es funktioniert zumindest für dieses Beispiel, aber es ist ziemlich hacky so bitte testen und keine Versprechungen :-)

import sys

def excepthook_wrapper(type, value, traceback):
    if len(value.args) == 2:
        name, msg = value.args
        value.args = (msg,)
        sys.__excepthook__(name, value, traceback)
    else:
        sys.__excepthook__(type, value, traceback)

sys.excepthook = excepthook_wrapper

( Edita: Ich bin nicht realmente glücklich damit, weil nun auch "normale" Ausnahmen mit zwei Argumenten anders behandelt werden. Mögliche Lösung, 'markieren' Sie Ihre speziellen Exceptions, indem Sie "PICKLED" als erstes Argument übergeben und dann darauf prüfen, anstatt auf die Länge der args .)

Und erstellen Sie dann die Exception mit zwei Argumenten, dem Namen ( __module__.__class__ ) und die Exception Nachricht ( str(e) ):

try:
    try:
        #print foo
        raise BadExc("bad exception error message", "a")
    except Exception, e:
        cls = e.__class__
        if hasattr(cls, '__module__'):
            name = '{0}.{1}'.format(cls.__module__, cls.__name__)
        else:
            name = cls.__name__
        raise Exception(name, str(e)), None, sys.exc_info()[2]
except Exception, f:
    pass

Dann dies:

import cPickle
a = cPickle.dumps(f)
l = cPickle.loads(a)
print "raising error"
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Drucke:

raising error
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    raise BadExc("bad exception error message", "a")
__main__.BadExc: bad exception error message

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