除了子句中的断点无权访问绑定异常

a_g*_*est 7 python breakpoints exception python-3.x pdb

考虑以下示例:

try:
    raise ValueError('test')
except ValueError as err:
    breakpoint()  # at this point in the debugger, name 'err' is not defined
Run Code Online (Sandbox Code Playgroud)

在这里,进入断点后,调试器无权访问绑定到的异常实例err

$ python test.py 
--Return--
> test.py(4)<module>()->None
-> breakpoint()
(Pdb) p err
*** NameError: name 'err' is not defined
Run Code Online (Sandbox Code Playgroud)

为什么会这样?如何访问异常实例?目前我正在使用以下解决方法,但感觉很尴尬:

$ python test.py 
--Return--
> test.py(4)<module>()->None
-> breakpoint()
(Pdb) p err
*** NameError: name 'err' is not defined
Run Code Online (Sandbox Code Playgroud)

有趣的是,使用此版本,我还可以err在调试器中向上移动一帧时访问绑定异常:

$ python test.py 
--Return--
> test.py(5)_tmp()->None
-> breakpoint()
(Pdb) up
> test.py(6)<module>()
-> _tmp()
(Pdb) p err
ValueError('test')
Run Code Online (Sandbox Code Playgroud)

拆卸通过 dis

在下面我比较了两个版本,一个breakpoint直接使用,另一个将其包装在自定义函数中_breakpoint

try:
    raise ValueError('test')
except ValueError as err:
    def _tmp():
        breakpoint()
    _tmp()
    # (lambda: breakpoint())()  # or this one alternatively
Run Code Online (Sandbox Code Playgroud)

dis除了一些内存位置和函数名称之外,输出是相似的:

差异

所以它必须是允许pdb引用绑定异常实例的附加堆栈帧。但是不清楚为什么会这样,因为在except块内任何东西都可以引用绑定的异常实例。

a_g*_*est 8

breakpoint()不是断点,因为它在此函数调用的确切位置停止执行。相反,它是一种简写import pdb; pdb.set_trace(),它将在下一行代码(它sys.settrace在幕后调用)停止执行。由于except块内没有更多代码,因此在退出该块执行将停止,因此名称err已被删除。通过在except块之后添加一行代码可以更清楚地看到这一点:

try:
    raise ValueError('test')
except ValueError as err:
    breakpoint()
print()
Run Code Online (Sandbox Code Playgroud)

这给出了以下内容:

$ python test.py 
> test.py(5)<module>()
-> print()
Run Code Online (Sandbox Code Playgroud)

这意味着解释器即将执行第print()5 行中的语句,并且它已经执行了之前的所有内容(包括删除 name err)。

当使用另一个函数来包装时,breakpoint()解释器将在该return函数发生时停止执行,因此该except块尚未退出(并且err仍然可用):

$ python test.py 
--Return--
> test.py(5)<lambda>()->None
-> (lambda: breakpoint())()
Run Code Online (Sandbox Code Playgroud)

except块的退出也可以通过在pass之后放置一个额外的语句来延迟breakpoint()

$ python test.py 
> test.py(5)<module>()
-> print()
Run Code Online (Sandbox Code Playgroud)

这导致:

$ python test.py 
> test.py(5)<module>()
-> pass
(Pdb) p err
ValueError('test')
Run Code Online (Sandbox Code Playgroud)

请注意,pass必须放在单独的行上,否则将被跳过:

$ python test.py 
--Return--
> test.py(4)<module>()->None
-> breakpoint(); pass
(Pdb) p err
*** NameError: name 'err' is not defined
Run Code Online (Sandbox Code Playgroud)

注意--Return--这意味着解释器已经到达模块的末尾。