python how to re-raise an exception which is already caught?
1 2 3 4 5 6 7 8 9 10 11 12 13 | import sys def worker(a): try: return 1 / a except ZeroDivisionError: return None def master(): res = worker(0) if not res: print(sys.exc_info()) raise sys.exc_info()[0] |
作为上面的代码段,我有许多类似于worker的函数。他们已经有了自己的Try-Except块来处理异常。然后一个主函数将调用每个工人。现在,sys.exc_info()返回全部无到3个元素,如何在master函数中重新引发异常?我使用的是python 2.7
一个更新:我有1000多个工人,有些工人的逻辑非常复杂,他们可以同时处理多种类型的异常。所以我的问题是,我能不能从大师那里提出这些例外,而不是编辑作品?
你想做的事行不通。一旦您处理了一个异常(不重新引发它),该异常以及伴随的状态将被清除,因此无法访问它。如果您希望异常保持活动状态,则必须要么不处理它,要么手动保持它的活动状态。
这不是很容易在文档中找到的(关于cpython的底层实现细节有点简单,但理想情况下我们想知道语言定义了什么python),但它就在那里,隐藏在
… This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
Before an except clause’s suite is executed, details about the exception are stored in the
sys module and can be accessed viasys.exc_info() .sys.exc_info() returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section The standard type hierarchy) identifying the point in the program where the exception occurred.sys.exc_info() values are restored to their previous values (before the call) when returning from a function that handled an exception.
此外,这确实是异常处理程序的要点:当一个函数处理一个异常时,对于该函数之外的世界,它看起来没有发生异常。这在python中比在其他许多语言中更重要,因为python使用异常非常混乱,每个
所以,最简单的方法就是改变工作人员不处理异常(或者记录然后重新引发异常,或者其他),并让异常处理按照它的意图工作。
有些情况下你不能这样做。例如,如果您的实际代码正在后台线程中运行工作线程,则调用方将看不到异常。在这种情况下,您需要手动将其传回。对于一个简单的示例,让我们更改工作函数的API以返回值和异常:
1 2 3 4 5 6 7 8 9 10 11 | def worker(a): try: return 1 / a, None except ZeroDivisionError as e: return None, e def master(): res, e = worker(0) if e: print(e) raise e |
很明显,你可以把这个扩展到更大的范围来返回整个
如果您查看
如果你不能修改工人,你基本上就走运了。当然,您可以编写一些可怕的代码来在运行时对工作人员进行修补(使用
没有测试过,但我怀疑你可以这样做。根据变量的范围,你必须改变它,但我想你会明白的
1 2 3 4 | try: something except Exception as e: variable_to_make_exception = e |
…..稍后使用变量
使用这种方法处理错误的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | errors = {} try: print(foo) except Exception as e: errors['foo'] = e try: print(bar) except Exception as e: errors['bar'] = e print(errors) raise errors['foo'] |
输出…
1 2 3 4 5 | {'foo': NameError("name 'foo' is not defined",), 'bar': NameError("name 'bar' is not defined",)} Traceback (most recent call last): File"<input>", line 13, in <module> File"<input>", line 3, in <module> NameError: name 'foo' is not defined |
在您的情况下,
如果你不能自己编辑工人的功能,我认为你做的不多。如果这些解决方案既能在代码中工作,也能在控制台上工作,那么您可能能够使用这个答案中的一些解决方案。
上面的krflol代码有点像C处理异常的方式——有一个全局变量,每当发生异常时,它都会被分配一个数字,稍后可以交叉引用该数字来确定异常是什么。这也是一个可能的解决方案。
但是,如果您愿意编辑工作函数,那么将异常升级到调用该函数的代码实际上非常简单:
1 2 3 4 5 | try: # some code except: # some response raise |
如果在
1 2 3 | except Exception as e: # some code raise e |