use*_*747 8 python ipython python-3.x pdb ipdb
Python(和 ipython)具有非常强大的事后调试功能,允许在回溯的每个范围内进行变量检查和命令执行。up/down 调试器命令允许更改最终异常的堆栈跟踪的帧,但是__cause__按照raise ... from ... 语法定义的那个异常呢?
Python 3.7.6 (default, Jan 8 2020, 13:42:34)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.11.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: def foo():
...: bab = 42
...: raise TypeError
...:
In [2]: try:
...: foo()
...: except TypeError as err:
...: barz = 5
...: raise ValueError from err
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-dd046d7cece0> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
<ipython-input-1-da9a05838c59> in foo()
2 bab = 42
----> 3 raise TypeError
4
TypeError:
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
<ipython-input-2-dd046d7cece0> in <module>
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError from err
6
ValueError:
In [3]: %debug
> <ipython-input-2-dd046d7cece0>(5)<module>()
2 foo()
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError from err
6
ipdb> barz
5
ipdb> bab
*** NameError: name 'bab' is not defined
ipdb> down
*** Newest frame
ipdb> up
*** Oldest frame
Run Code Online (Sandbox Code Playgroud)
有没有办法bab从调试器访问?
编辑:我意识到事后调试不仅仅是 ipython 和 ipdb 的一个功能,它实际上是 vanilla pdb 的一部分。以上也可以通过将代码放入脚本中testerr.py,运行python -m pdb testerr.py运行来复现continue。错误后,它说
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
Run Code Online (Sandbox Code Playgroud)
并在同一地点提供调试器。
您可以使用该with_traceback(tb)方法来保留原始异常的回溯:
try:
foo()
except TypeError as err:
barz = 5
raise ValueError().with_traceback(err.__traceback__) from err
Run Code Online (Sandbox Code Playgroud)
请注意,我已更新代码以引发异常实例而不是异常类。
这是iPython 中的完整代码片段:
In [1]: def foo():
...: bab = 42
...: raise TypeError()
...:
In [2]: try:
...: foo()
...: except TypeError as err:
...: barz = 5
...: raise ValueError().with_traceback(err.__traceback__) from err
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-a5a6d81e4c1a> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
<ipython-input-1-ca1efd1bee60> in foo()
2 bab = 42
----> 3 raise TypeError()
4
TypeError:
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
<ipython-input-2-a5a6d81e4c1a> in <module>
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError().with_traceback(err.__traceback__) from err
6
<ipython-input-2-a5a6d81e4c1a> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
4 barz = 5
5 raise ValueError().with_traceback(err.__traceback__) from err
<ipython-input-1-ca1efd1bee60> in foo()
1 def foo():
2 bab = 42
----> 3 raise TypeError()
4
ValueError:
In [3]: %debug
> <ipython-input-1-ca1efd1bee60>(3)foo()
1 def foo():
2 bab = 42
----> 3 raise TypeError()
4
ipdb> bab
42
ipdb> u
> <ipython-input-2-a5a6d81e4c1a>(2)<module>()
1 try:
----> 2 foo()
3 except TypeError as err:
4 barz = 5
5 raise ValueError().with_traceback(err.__traceback__) from err
ipdb> u
> <ipython-input-2-a5a6d81e4c1a>(5)<module>()
2 foo()
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError().with_traceback(err.__traceback__) from err
6
ipdb> barz
5
Run Code Online (Sandbox Code Playgroud)
解决@user2357112supportsMonica 的第一条评论,如果您希望避免在日志中多次转储原始异常的回溯,可以使用raise from None. 但是,正如@user2357112supportsMonica 的第二条评论所述,这隐藏了原始异常的消息。在您不是事后调试而是检查打印的回溯的常见情况下,这尤其成问题。
try:
foo()
except TypeError as err:
barz = 5
raise ValueError().with_traceback(err.__traceback__) from None
Run Code Online (Sandbox Code Playgroud)
这是iPython 中的代码片段:
In [4]: try:
...: foo()
...: except TypeError as err:
...: barz = 5
...: raise ValueError().with_traceback(err.__traceback__) from None
...:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-6-b090fb9c510e> in <module>
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError().with_traceback(err.__traceback__) from None
6
<ipython-input-6-b090fb9c510e> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
4 barz = 5
5 raise ValueError().with_traceback(err.__traceback__) from None
<ipython-input-2-ca1efd1bee60> in foo()
1 def foo():
2 bab = 42
----> 3 raise TypeError()
4
ValueError:
In [5]: %debug
> <ipython-input-2-ca1efd1bee60>(3)foo()
1 def foo():
2 bab = 42
----> 3 raise TypeError()
4
ipdb> bab
42
ipdb> u
> <ipython-input-6-b090fb9c510e>(2)<module>()
1 try:
----> 2 foo()
3 except TypeError as err:
4 barz = 5
5 raise ValueError().with_traceback(err.__traceback__) from None
ipdb> u
> <ipython-input-6-b090fb9c510e>(5)<module>()
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError().with_traceback(err.__traceback__) from None
6
ipdb> barz
5
Run Code Online (Sandbox Code Playgroud)
Raisingfrom None是必需的,否则链接将隐式完成,将原始异常附加为新异常的__context__属性。请注意,这与__cause__显式完成链接时设置的属性不同。
In [6]: try:
...: foo()
...: except TypeError as err:
...: barz = 5
...: raise ValueError().with_traceback(err.__traceback__)
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-ee78991171cb> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
<ipython-input-2-ca1efd1bee60> in foo()
2 bab = 42
----> 3 raise TypeError()
4
TypeError:
During handling of the above exception, another exception occurred:
ValueError Traceback (most recent call last)
<ipython-input-5-ee78991171cb> in <module>
3 except TypeError as err:
4 barz = 5
----> 5 raise ValueError().with_traceback(err.__traceback__)
6
<ipython-input-5-ee78991171cb> in <module>
1 try:
----> 2 foo()
3 except TypeError as err:
4 barz = 5
5 raise ValueError().with_traceback(err.__traceback__)
<ipython-input-2-ca1efd1bee60> in foo()
1 def foo():
2 bab = 42
----> 3 raise TypeError()
4
ValueError:
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
500 次 |
| 最近记录: |