这是我之前提出的问题 Hang in Python script using SQLAlchemy and multiprocessing 的跟进。正如在那个问题中讨论的那样,将异常进行pickling在Python中是有问题的。这通常不是一个问题,但有一种情况,当Python多进程模块中发生错误时,它就会成为一个问题。由于多进程通过pickling移动对象,如果在多进程过程中发生错误,则整个进程可能会挂起,就像那个问题中所演示的那样。
一种可能的方法是修复所有有问题的异常,就像在那个问题中讨论的那样。这并不容易,因为人们很难预先知道哪些异常可能被调用。另一种方法是捕获异常,构造等效的无害异常,然后重新抛出异常,正如lbolla在回答中建议的那样。
然而,我不确定该如何做。考虑以下代码。
更普遍的做法是,在异常名称前加上异常的名称,而不是
或者,可以使用
一种可能的方法是修复所有有问题的异常,就像在那个问题中讨论的那样。这并不容易,因为人们很难预先知道哪些异常可能被调用。另一种方法是捕获异常,构造等效的无害异常,然后重新抛出异常,正如lbolla在回答中建议的那样。
然而,我不确定该如何做。考虑以下代码。
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]
这段代码将异常进行序列化并反序列化,然后抛出它,从而产生错误。
raising error
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
Exception: BadExc: bad exception error message
感谢Glenn Maynard在“Python中的“内部异常”(带有回溯)”中提供的答案。该答案包含了重要的内容,即回溯、错误信息和异常类型,因此可能是最好的解决方案。但理想情况下,我希望得到与原始异常完全相同的输出结果,即:
Traceback (most recent call last):
File "<stdin>", line 11, in <module>
__main__.BadExc: bad exception error message
更普遍的做法是,在异常名称前加上异常的名称,而不是
Exception
。这可行吗?或者,可以使用
print foo
语句代替 BadExc
类,这会导致 NameError
异常。然而,这种异常不需要特殊处理。
sys.excepthook
这样的“全局”东西来解决这个问题,正如你所指出的,它有问题。我曾经模糊地想过,也许有一种方法可以通过覆盖某些属性或方法来欺骗解释器,使其认为抛出的异常是BadExc
类型,但我不知道是否可以实现,也不知道如何实现。 - Faheem Mitha