Pdb 转到异常中的异常帧

2023-11-24

我正在调试一个名为a.py使用PDB

def f(x) :
    x / x

def g(x) :
    try :
        f(x)
    except Exception as e :
        assert 0

g(0)

当我使用运行程序时python3 -m pdb a.py,程序停止于assert 0行,我得到以下错误信息:

Traceback (most recent call last):
  File "/tmp/a.py", line 6, in g
    f(x)
  File "/tmp/a.py", line 2, in f
    x / x
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib64/python3.6/pdb.py", line 1667, in main
    pdb._runscript(mainpyfile)
  File "/usr/lib64/python3.6/pdb.py", line 1548, in _runscript
    self.run(statement)
  File "/usr/lib64/python3.6/bdb.py", line 434, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "/tmp/a.py", line 11, in <module>
    g(0)
  File "/tmp/a.py", line 9, in g
    assert 0
AssertionError

堆栈是(使用显示bt命令):

(Pdb) bt
  /usr/lib64/python3.6/pdb.py(1667)main()
-> pdb._runscript(mainpyfile)
  /usr/lib64/python3.6/pdb.py(1548)_runscript()
-> self.run(statement)
  /usr/lib64/python3.6/bdb.py(434)run()
-> exec(cmd, globals, locals)
  <string>(1)<module>()->None
  /tmp/a.py(11)<module>()->None
-> g(0)
> /tmp/a.py(9)g()
-> assert 0
(Pdb) 

问题是,我无法去函数 f 进行调试x / x简单地使用up and down,因为我的堆栈在 g 函数处结束。

我应该如何在异常中调试此类异常?异常中的异常又如何……?


tl;dr:即使您已经进入外部异常的事后调试,您也可以调试内部异常。操作方法如下:

  1. 进入交互模式从pdb (type interact进入pdb迅速的)。
  2. Run:
    import pdb, sys; pdb.post_mortem(sys.last_value.__context__.__traceback__)
    
    Note:
    • Replace __context__ with __cause__如果您的异常是显式链接的;还追加更多__context__s or __cause__s 如果嵌套得更深。
    • 如果您正在检查已处理的异常(在 try-catch 中捕获的异常),请替换sys.last_value with sys.exc_info()[1]。如果您不确定,请在继续之前检查异常值。 (谢谢@医生在评论中指出这一点)
  3. 这开始了一个新的pdb允许您调试内部异常的会话。

以下是对这项工作为何有效的详细解释。在深入讨论解决方案之前,我首先解释一些相关概念:


连锁异常

这里的“例外中的例外”被称为连锁异常。异常可以显式或隐式链接:

>>>: try:
...:     raise ZeroDivisionError
...: except Exception as inner_exc:
...:     raise ValueError  # implicit chaining
...:
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-6-1ae22e81c853> in <module>
      1 try:
----> 2     raise ZeroDivisionError
      3 except Exception as inner_exc:

ZeroDivisionError:

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-6-1ae22e81c853> in <module>
      2     raise ZeroDivisionError
      3 except Exception as inner_exc:
----> 4     raise ValueError  # implicit chaining

ValueError:


>>>: try:
...:     raise ZeroDivisionError
...: except Exception as inner_exc:
...:     raise ValueError from inner_exc  # explicit chaining
...:
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-5-63c49fcb10a2> in <module>
      1 try:
----> 2     raise ZeroDivisionError
      3 except Exception as inner_exc:

ZeroDivisionError:

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

ValueError                                Traceback (most recent call last)
<ipython-input-5-63c49fcb10a2> in <module>
      2     raise ZeroDivisionError
      3 except Exception as inner_exc:
----> 4     raise ValueError from inner_exc  # explicit chaining

ValueError:

如果我们将外部异常捕获为outer_exc,然后我们可以通过检查内部异常outer_exc.__cause__(如果显式链接)或outer_exc.__context__(如果隐式链接)。


事后调试

运行脚本python -m pdb允许Python调试器进入事后调试异常模式。这里的“事后”是指“异常发生后”。您可以通过运行以下命令从 IPython 控制台或 Jupyter 笔记本中执行相同的操作%debug magic.

如果您有权访问回溯对象,您还可以手动进入事后调试模式。幸运的是,回溯对象存储在异常对象本身上__traceback__属性:

>>> try:
...     raise ZeroDivisionError:
... except Exception as e:
...     # Variable `e` is local to this block, so we store it in another variable
...     # to extend its lifetime.
...     exc = e

>>> import pdb
>>> pdb.post_mortem(exc.__traceback__)
> <ipython-input-8-e5b5ed89e466>(2)<module>()
-> raise ZeroDivisionError
(Pdb)

调试链式异常

现在我们可以尝试调试链式异常!假设我们已经处于外部异常的事后调试模式。我们需要做的是:

  1. 获取外部异常对象;
  2. 访问内部异常对象,并获取其回溯;
  3. Call pdb.post_mortem()在该回溯对象上。 这就是我们所做的:
# First, enter interactive mode to execute commands.
(Pdb) interact
*interactive*
# The current exception is stored in `sys.exc_info()`.  This gives back a tuple
# of (exception type, exception value, traceback).
>>> import sys
>>> sys.exc_info()
(<class 'AssertionError'>, AssertionError(), <traceback object at 0x10c683e00>)
>>> sys.exc_info()[1]
AssertionError()
# In our case, the inner exception is implicitly chained.  Access it through
# the `__context__` attribute.
>>> sys.exc_info()[1].__context__
ZeroDivisionError('division by zero')
# Get its traceback, and enter post-mortem debugging.
>>> sys.exc_info()[1].__context__.__traceback__
<traceback object at 0x10c683c80>
>>> import pdb
>>> pdb.post_mortem(sys.exc_info()[1].__context__.__traceback__)
> test.py(2)f()
-> x / x
(Pdb)

你有它!您现在可以使用正常调试内部异常pdb命令,例如遍历堆栈或检查局部变量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Pdb 转到异常中的异常帧 的相关文章

  • 如何手动计算分类交叉熵?

    当我手动计算二元交叉熵时 我应用 sigmoid 来获取概率 然后使用交叉熵公式并平均结果 logits tf constant 1 1 0 1 2 labels tf constant 0 0 1 1 1 probs tf nn sigm
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程
  • Django 的内联管理:一个“预填充”字段

    我正在开发我的第一个 Django 项目 我希望用户能够在管理中创建自定义表单 并向其中添加字段当他或她需要它们时 为此 我在我的项目中添加了一个可重用的应用程序 可在 github 上找到 https github com stephen
  • 处理 Python 行为测试框架中的异常

    我一直在考虑从鼻子转向行为测试 摩卡 柴等已经宠坏了我 到目前为止一切都很好 但除了以下之外 我似乎无法找出任何测试异常的方法 then It throws a KeyError exception def step impl contex
  • 跟踪 pypi 依赖项 - 谁在使用我的包

    无论如何 是否可以通过 pip 或 PyPi 来识别哪些项目 在 Pypi 上发布 可能正在使用我的包 也在 PyPi 上发布 我想确定每个包的用户群以及可能尝试积极与他们互动 预先感谢您的任何答案 即使我想做的事情是不可能的 这实际上是不
  • 删除flask中的一对一关系

    我目前正在使用 Flask 开发一个应用程序 并且在删除一对一关系中的项目时遇到了一个大问题 我的模型中有以下结构 class User db Model tablename user user id db Column db String
  • Pandas 日期时间格式

    是否可以用零后缀表示 pd to datetime 似乎零被删除了 print pd to datetime 2000 07 26 14 21 00 00000 format Y m d H M S f 结果是 2000 07 26 14
  • 使用 xlrd 打开 BytesIO (xlsx)

    我正在使用 Django 需要读取上传的 xlsx 文件的工作表和单元格 使用 xlrd 应该可以 但因为文件必须保留在内存中并且可能不会保存到我不知道如何继续的位置 本例中的起点是一个带有上传输入和提交按钮的网页 提交后 文件被捕获req
  • 从Python中的字典列表中查找特定值

    我的字典列表中有以下数据 data I versicolor 0 Sepal Length 7 9 I setosa 0 I virginica 1 I versicolor 0 I setosa 1 I virginica 0 Sepal
  • Python,将函数的输出重定向到文件中

    我正在尝试将函数的输出存储到Python中的文件中 我想做的是这样的 def test print This is a Test file open Log a file write test file close 但是当我这样做时 我收到
  • 如何通过 TLS 1.2 运行 django runserver

    我正在本地 Mac OS X 机器上测试 Stripe 订单 我正在实现这段代码 stripe api key settings STRIPE SECRET order stripe Order create currency usd em
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • 使用特定颜色和抖动在箱形图上绘制数据点

    我有一个plotly graph objects Box图 我显示了箱形 图中的所有点 我需要根据数据的属性为标记着色 如下所示 我还想抖动这些点 下面未显示 Using Box我可以绘制点并抖动它们 但我不认为我可以给它们着色 fig a
  • 根据列 value_counts 过滤数据框(pandas)

    我是第一次尝试熊猫 我有一个包含两列的数据框 user id and string 每个 user id 可能有多个字符串 因此会多次出现在数据帧中 我想从中导出另一个数据框 一个只有那些user ids列出至少有 2 个或更多string
  • 如何解决 PDFBox 没有 unicode 映射错误?

    我有一个现有的 PDF 文件 我想使用 python 脚本将其转换为 Excel 文件 目前正在使用PDFBox 但是存在多个类似以下错误 org apache pdfbox pdmodel font PDType0Font toUnico
  • 实现 XGboost 自定义目标函数

    我正在尝试使用 XGboost 实现自定义目标函数 在 R 中 但我也使用 python 所以有关 python 的任何反馈也很好 我创建了一个返回梯度和粗麻布的函数 它工作正常 但是当我尝试运行 xgb train 时它不起作用 然后 我
  • 使用for循环时如何获取前一个元素? [复制]

    这个问题在这里已经有答案了 可能的重复 Python 循环内的上一个和下一个值 https stackoverflow com questions 1011938 python previous and next values inside
  • NoSuchBeanDefinitionException:没有合格的 bean 类型

    当调用我的 GET 请求 模式计算 时 我收到此错误 我不明白为什么 我的依赖项注入是正确的 org springframework beans factory NoSuchBeanDefinitionException No qualif
  • 如何应用一个函数 n 次? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 假设我有一个函数 它接受一个参数并返回相同类型的结果 def increment x return x 1 如何制作高阶函数repeat可以
  • 更改 Tk 标签小部件中单个单词的颜色

    我想更改 Tkinter 标签小部件中单个单词的字体颜色 我知道可以使用文本小部件来实现与我想要完成的类似的事情 例如使单词 YELLOW 显示为黄色 self text tag config tag yel fg clr yellow s

随机推荐