gpt4 book ai didi

python - 如何从异常中将 "jump"放入堆栈帧?

转载 作者:太空宇宙 更新时间:2023-11-03 16:07:23 25 4
gpt4 key购买 nike

有一个引发的异常我想跳到那个框架。为了更好地解释我的意思,我写了这篇文章:

假设我有以下代码:

from multiprocessing import Pool
import sys

# Setup debugger
def raiseDebugger(*args):
""" http://code.activestate.com/recipes/65287-automatically-start-the-
debugger-on-an-exception/ """

import traceback, pdb
traceback.print_exception(*args)
pdb.pm()

sys.excepthook = raiseDebugger


# Now start with the question

def faulty(i):
return 1 / i


with Pool() as pool:
pool.map(faulty, range(6))

这毫不奇怪地导致:

multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 119, in worker
result = (True, func(*args, **kwds))
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar
return list(map(*args))
File "test2.py", line 19, in faulty
return 1 / i
ZeroDivisionError: division by zero
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "test2.py", line 23, in <module>
pool.map(faulty, range(6))
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 260, in map
return self._map_async(func, iterable, mapstar, chunksize).get()
File "/home/bin/conda/lib/python3.5/multiprocessing/pool.py", line 608, in get
raise self._value
ZeroDivisionError: division by zero
> /home/bin/conda/lib/python3.5/multiprocessing/pool.py(608)get()
-> raise self._value
(Pdb)

现在为了调试问题,我想“跳”到最初引发异常(ZeroDivisionError)的框架。

原始异常在 self._value 下仍然可用,并带有 self._value.__traceback__

最佳答案

pm (或 post_mortem )调用来自 sys.exc_info 的 value 字段,并且 post_mortem 的默认调用是在该值的 __traceback__ 上完成的。但是,如果您想访问底层对象,则需要访问其 __context__。鉴于此代码示例:

import pdb
import sys
import traceback

def top():
value = 1
raise Exception('this always fails')

def bottom():
try:
top()
except Exception as bot_ex:
x = {}
return x['nothing']

try:
bottom()
except Exception as main_ex:
pdb.post_mortem()

运行代码。 main_ex 类似于您的 self._value

> /tmp/foo.py(14)bottom()
-> return x['nothing']
(Pdb) main_ex
KeyError('nothing',)
(Pdb) pdb.post_mortem(main_ex.__traceback__)
> /tmp/foo.py(14)bottom()
-> return x['nothing']

请注意,我们在同一位置有一个新的 pdb 提示符,这是最初引发异常的位置。如果我们需要进一步向上,让我们尝试使用 __context__:

(Pdb) c
(Pdb) pdb.post_mortem(main_ex.__context__.__traceback__)
> /tmp/foo.py(7)top()
-> raise Exception('this always fails')

如果需要,请继续重复,直到到达所需的目标上下文/回溯。

<小时/>

现在对于多处理情况,我不知道这会产生这么大的差异,因为问题暗示了一些一般性的东西(我如何从异常“跳转”到堆栈帧?),但事实证明 multiprocessing 中的具体细节一切都变得不同了。

在 Python 3.4 中,采取了一种解决方法,仅将回溯显示为字符串;由于回溯实际上有多少内容,正如 Python 跟踪器上的 issue 13831 中所讨论的那样,传达所有这些内容被证明是困难的,因此进行了黑客攻击,将 __cause__ 属性引入当前异常,但它不是完整的 __traceback__,因为正如我所怀疑的,它只是具有字符串表示形式。

无论如何,这就是会发生的事情:

(Pdb) !import pdb
(Pdb) !self._value.__cause__
RemoteTraceback('\n"""\nTraceback (most recent call last):...',)
(Pdb) !type(self._value.__cause__)
<class 'multiprocessing.pool.RemoteTraceback'>
(Pdb) !self._value.__cause__.__traceback__
(Pdb) !self._value.__cause__.__context__

因此,在他们弄清楚如何使所有这些状态跨越进程边界之前,这实际上是不可能的。

关于python - 如何从异常中将 "jump"放入堆栈帧?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39650793/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com