当一条线上的多条停靠点跟踪时,python停止在哪条线上?
考虑以下两个例子:当一条线上的多条停靠点跟踪时,python停止在哪条线上?
x = 1; y = 2; z = 3
和:
for i in range(3): print(i)
在后者,如果你通过这个在调试步骤一样PDB,你会把它会停在print(i)
在循环的每次迭代。
但是在第一个例子中,它会停止一次。
进一步调查,拆分多语句行,我们看到实际上有两个条目用于第一行co_lnotab
。但dis.dis()
就在于此。
至于对于循环,lnotab
中只有一行,但是您停在每个迭代的位置偏移10处在跳转的目标处。那么,即使行号没有改变,什么会触发停止?
import dis
>>> x = compile('x = 1; y = 2; z = 3', 'foo', 'exec')
>>> x.co_lnotab
b'\x04\x00\x04\x00'
>>> dis.dis(x)
1 0 LOAD_CONST 0 (1)
2 STORE_NAME 0 (x)
4 LOAD_CONST 1 (2)
6 STORE_NAME 1 (y)
8 LOAD_CONST 2 (3)
10 STORE_NAME 2 (z)
12 LOAD_CONST 3 (4)
14 STORE_NAME 3 (a)
16 LOAD_CONST 4 (None)
18 RETURN_VALUE
>>> y = compile('for i in range(3): print(i)', 'foo', 'exec')
>>> y.co_lnotab
b'\x0e\x00'
>>> dis.dis(y)
1 0 SETUP_LOOP 24 (to 26)
2 LOAD_NAME 0 (range)
4 LOAD_CONST 0 (3)
6 CALL_FUNCTION 1
8 GET_ITER
>> 10 FOR_ITER 12 (to 24)
12 STORE_NAME 1 (i)
14 LOAD_NAME 2 (print)
16 LOAD_NAME 1 (i)
18 CALL_FUNCTION 1
20 POP_TOP
22 JUMP_ABSOLUTE 10
>> 24 POP_BLOCK
>> 26 LOAD_CONST 1 (None)
28 RETURN_VALUE
>>>
该逻辑的源代码在哪里?我看过Python C代码,但找不到它,请在ceval.c
中寻找PyTrace_LINE
。
编辑:
基于user2357112的答案和阅读代码建议在那里,我能够验证的代码的每个语句是一个可以停止/跟踪。 我用我的新的Python汇编,pyc-xasm,修改字节码这样:
2:
LOAD_CONST (1)
STORE_NAME (x)
JUMP_FORWARD L2B
L2A:
2:
LOAD_CONST (2)
STORE_NAME (y)
JUMP_FORWARD L2D
L2B:
JUMP_ABSOLUTE L2A
L2C:
2:
LOAD_CONST (3)
STORE_NAME (z)
JUMP_FORWARD L3
L2D:
JUMP_ABSOLUTE L2C
L3:
3:
LOAD_NAME (x)
LOAD_NAME (y)
BINARY_ADD
LOAD_NAME (z)
BINARY_ADD
PRINT_ITEM
PRINT_NEWLINE
LOAD_CONST (None)
RETURN_VALUE
并运行,这将导致Python来的每一行之前停止。
PDB跟踪使用通过sys.settrace
设置的跟踪功能。有一个数字,将触发跟踪功能的事件,但你看的那些都是线事件:
'line'
的解释即将执行代码新行或者重新执行循环条件。局部跟踪功能被调用; arg是None
;返回值指定新的本地跟踪功能。请参阅Objects/lnotab_notes.txt
以了解其工作原理的详细说明。
正如文档所述,您可以在Objects/lnotab_notes.txt
中看到线事件触发器的更详细的解释。最相关的部分是
我们通过如果 co_lnotab表明我们已经跃升为开头的行的,即只要求向前跳跃路线追踪功能解决这个问题如果当前的 指令偏移量与由 co_lnotab给出的行开始偏移量相匹配。但是,对于向后跳转,我们总是调用线跟踪功能 ,该功能可让调试器在对环路保护的每次评估(通常 不会成为一行中的第一个操作码)时停止。
因此,PDB将在行的开始处暂停,或者如果执行在代码中向后跳转。
如果你想看到触发线事件的源代码,它在Python/ceval.c
maybe_call_line_trace
下。 PDB的源代码可预见地在Lib/pdb.py
之下。
我很好奇你是什么让你看到这一点。你在做什么? –
很长一段时间,我一直在研究调试器,其中包括python调试器。请参阅https://pypi.python.org/pypi/trepan3k。 我想你应该可以在任何你想要的地方设置一个断点,这可以通过在函数中指定一个字节码偏移来完成。或者决定在多个报表中停止使用哪个报表。随着最近一些字节码操作工具的推进,我可以做到这一点。尽管如此,这还是很多的工作,并不一定涵盖所有情况。 – rocky
太棒了!我正在研究一个python调试器(字面上),您可能会感兴趣:https://github.com/alexmojaki/birdseye –