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块来处理异常。然后一个主函数将调用每个worker。现在,sys.exc_info()返回所有的None到3个元素,如何在主函数中重新引发异常?我使用的是Python 2.7
一个更新:我有1000多个工人,有些工人有非常复杂的逻辑,他们可能会同时处理多种类型的异常。所以我的问题是,我可以只从master中提出这些异常,而不是编辑作品吗?
发布于 2018-07-06 02:38:28
你想做的事不会奏效。一旦你处理了一个异常(没有重新引发它),这个异常和伴随的状态就被清除了,所以就没有办法访问它了。如果您希望异常保持活动状态,则必须不处理它,或者手动使其保持活动状态。
这并不容易在文档中找到(关于CPython的底层实现细节要容易一些,但理想情况下我们想知道该语言定义了什么),但它就在那里,埋藏在except参考中:
…这意味着必须为异常指定一个不同的名称,以便能够在except子句之后引用它。异常被清除是因为附加了回溯,它们与堆栈帧形成一个引用循环,使该帧中的所有本地变量保持活动状态,直到下一次垃圾收集发生。
在执行except子句的套件之前,有关异常的详细信息存储在sys模块中,可以通过sys.exc_info()访问这些信息。sys.exc_info()返回一个由exception类、exception实例和一个回溯对象(参见标准类型层次结构一节)组成的三元组,该对象标识了程序中发生异常的点。从处理异常的函数返回时,sys.exc_info()值将恢复为其先前的值(在调用之前)。
此外,这也是异常处理程序的真正意义所在:当一个函数处理异常时,对于该函数之外的世界来说,它看起来就像没有发生异常一样。这一点在Python语言中甚至比在其他语言中更重要,因为Python太过混杂地使用异常--每个for循环、每个hasattr调用等都会引发和处理异常,您不希望看到这些异常。
因此,要做到这一点,最简单的方法就是将工作线程更改为不处理异常(或者记录并重新引发异常,等等),并让异常处理按预期的方式工作。
在某些情况下,您不能这样做。例如,如果您的实际代码在后台线程中运行工作线程,调用者将看不到异常。在这种情况下,您需要手动传回它。举个简单的例子,让我们更改worker函数的API以返回值和异常:
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显然,您可以进一步扩展它以返回整个exc_info三元组,或者您想要的任何其他内容;我只是在示例中尽量保持简单。
如果你看一下像concurrent.futures这样的东西,你会发现它们是如何处理将运行在线程或进程池上的任务的异常传递回父级的(例如,当你等待Future时)。
如果你不能修改工人,你基本上是不走运的。当然,您可以编写一些可怕的代码来在运行时修补工作程序(通过使用inspect获取它们的源代码,然后使用ast解析、转换和重新编译它,或者直接深入字节码),但对于任何类型的生产代码来说,这几乎都不是一个好主意。
发布于 2018-07-06 02:42:21
在本例中,worker中的异常返回None。一旦发生这种情况,就不能再找回异常了。如果您的主函数知道每个函数的返回值应该是什么(例如,worker中的ZeroDivisionError返回None ),则可以手动重新引发异常。
如果你不能编辑worker函数本身,我不认为你能做太多。如果some of the solutions from this answer在代码和控制台上都能正常工作,那么您也可以使用它们。
krflol上面的代码有点像C处理异常的方式--有一个全局变量,每当异常发生时,都会分配一个数字,以后可以交叉引用这个数字来找出异常是什么。这也是一种可能的解决方案。
但是,如果您愿意编辑worker函数,那么将异常升级到调用该函数的代码实际上非常简单:
try:
# some code
except:
# some response
raise如果在catch块的末尾使用空白的raise,它将重新引发刚刚捕获的相同异常。或者,如果需要调试打印,您可以命名异常,并执行相同的操作,甚至引发不同的异常。
except Exception as e:
# some code
raise e发布于 2018-07-06 02:33:11
没有经过测试,但我怀疑你可以做这样的事情。根据变量的作用域,您必须对其进行更改,但我认为您会有所了解
try:
something
except Exception as e:
variable_to_make_exception = e使用变量时的.....later
使用这种方法处理错误的一个示例:
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']输出..
{'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 definedhttps://stackoverflow.com/questions/51197783
复制相似问题