考慮以下兩個例子:當一條線上的多條停靠點跟蹤時,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來的每一行之前停止。
我很好奇你是什麼讓你看到這一點。你在做什麼? –
很長一段時間,我一直在研究調試器,其中包括python調試器。請參閱https://pypi.python.org/pypi/trepan3k。 我想你應該可以在任何你想要的地方設置一個斷點,這可以通過在函數中指定一個字節碼偏移來完成。或者決定在多個報表中停止使用哪個報表。隨着最近一些字節碼操作工具的推進,我可以做到這一點。儘管如此,這還是很多的工作,並不一定涵蓋所有情況。 – rocky
太棒了!我正在研究一個python調試器(字面上),您可能會感興趣:https://github.com/alexmojaki/birdseye –