2012-01-18 7 views
3

これは私の質問Hang in Python script using SQLAlchemy and multiprocessingのフォローアップです。その質問で説明したように、Pythonでは例外を回避することは問題になります。これは通常問題ではありませんが、Pythonマルチプロセッシングモジュールでエラーが発生した場合があります。マルチプロセッシングはピクルリングでオブジェクトを動かすため、マルチプロセッシングプロセス内でエラーが発生した場合、その質問に示されているように、プロセス全体がハングアップする可能性があります。例外をキャッチして再呼び上げ

考えられるアプローチの1つは、その問題で説明されているように、すべての問題の例外を修正することです。これは容易ではない。なぜなら、例外が呼ばれる可能性があることを容易に事前に知ることができないからである。代替アプローチ(suggested by lbolla in an answer to the question)は、例外を捕捉し、同等の無害な例外を構築してから再スローすることです。 しかし、私はこれを行う方法が正確にわからない。次のコードを考えてみましょう。

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] 

このコードの漬物と例外をunpickles、それを投げ、Glenn Maynard's answer to "“Inner exception” (with traceback) in Python?"にエラーに

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

クレジットを与えます。 これには重要なことがあります。つまり、トレースバック、エラーメッセージ、例外の種類です。これが最善の方法です。しかし、理想的に私はむしろExceptionよりも前に例外の名前を持つ、より一般的に正確に元の例外のようなもの、すなわち

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

かを、したいと思います。これは可能ですか?

また、代わりにBadExcクラスで、1はNameErrorを与える代わりに、print fooステートメントを使用することができます。ただし、この例外は特別な処理を必要としません。

答えて

2

sys.excepthookを無効にすることで、目的を達成できます。それは、少なくともこの例では動作しますが、それはそうテストしてくださいかなりハックだと何の約束:-)

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 

編集:私は今、「通常の」例外ので、これで本当に満足していません可能な解決法は、argsの長さを調べる代わりに、最初の引数として "PICKLED"を渡して確認することで特別な例外を「タグ付け」します。

2つの引数を持つExceptionは、名前(__module__.__class__)とExceptionメッセージ(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 

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] 

プリント:

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 
+0

こんにちは、ロブ。回答ありがとうございます。 +1の努力をしていますが、私は実際にこのような方法で 'sys.excepthook'のような「グローバル」なものを使う考えが嫌いです。指摘するように、問題があります。私は、通訳者に、実際に実行できるかどうかわからないが、スローされた例外がいくつかの属性やメソッドを上書きすることによってBadExc型であると考えてしまうような方法があるかもしれないとぼんやりと考えていたそれをやる。 –

関連する問題