这是我的问题Hang in Python script using SQLAlchemy and multiprocessing的后续内容。正如在该问题中所讨论的,在Python中,腌制异常是有问题的。这通常不是问题,但有一种情况,就是在python多处理模块中发生错误的时候。由于多处理通过酸洗移动对象,如果在多处理过程中发生错误,整个过程可能会挂起,如该问题所示。
一种可能的方法是修复所有有问题的异常,如该问题中所讨论的那样。这并不容易,因为事先不能容易地知道可以调用哪些例外。另一种方法是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]
此代码对异常进行pickle和unpickle,然后将其抛出,发出错误
raising error
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
Exception: BadExc: bad exception error message
致Glenn Maynard's answer to "“Inner exception” (with traceback) in Python?"的积分。 这有重要的东西,即回溯,错误消息和异常类型,所以这可能是最好的。但理想情况下,我希望看起来与原始异常完全相同,即
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
__main__.BadExc: bad exception error message
或更一般地说,前面是异常的名称,而不是Exception
。这可能吗?
或者,可以使用BadExc
语句代替print foo
类,而不是NameError
语句,这会产生{{1}}。但是,此异常不需要特殊处理。
答案 0 :(得分:2)
您可以覆盖sys.excepthook
以达到您想要的效果。它至少适用于这个例子,但它非常hacky所以请测试,没有承诺: - )
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
(编辑:我不是真的对此感到满意,因为现在'正常'有两个参数的异常也会得到不同的处理。可能的解决方案,'标记'你的通过将“PICKLED”作为第一个参数传递然后检查它而不是检查args
的长度来确定异常。)
然后使用两个参数创建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