Catching unpickleable exceptions and re-raising
这是我的问题的后续使用SQLAlchemy和多处理在Python脚本中挂起。正如在该问题中所讨论的,在Python中,腌制异常是有问题的。这通常不是问题,但有一种情况,就是在python多处理模块中发生错误的时候。由于多处理通过酸洗移动对象,如果在多处理过程中发生错误,整个过程可能会挂起,如该问题所示。
一种可能的方法是修复所有有问题的异常,如该问题中所讨论的那样。这并不容易,因为事先不能容易地知道可以调用哪些例外。 lbolla在回答问题时提出的另一种方法是捕获异常,构造一个等效的无害异常,然后重新抛出。
但是,我不确定如何做到这一点。请考虑以下代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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和unpickles,然后将其抛出,从而产生错误
1 2 3 4 | raising error Traceback (most recent call last): File"<stdin>", line 11, in <module> Exception: BadExc: bad exception error message |
归功于Glenn Maynard对Python中"内部异常"(带回溯)的回答?"
这有重要的东西,即回溯,错误消息和异常类型,所以这可能是最好的。但理想情况下,我喜欢看起来与原始异常完全相同的东西,即
1 2 3 | Traceback (most recent call last): File"<stdin>", line 11, in <module> __main__.BadExc: bad exception error message |
或者更一般地说,前面有例外的名称,而不是
或者,代替
您可以覆盖
1 2 3 4 5 6 7 8 9 10 11 | 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"作为第一个参数传递'标记'你的特殊异常,然后检查它, 而不是检查
然后创建带有两个参数的
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
然后这个:
1 2 3 4 5 | 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] |
打印:
1 2 3 4 5 | 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 |