讀「每個程序員應該知道的97件事」我發現有關代碼分析工具的有趣文章。使用反彙編程序來調試錯誤Python
作者聲稱,從Python標準庫彙編器可以調試你的每一天代碼
這裏去非常有用: 「有一件事這個庫(Python標準庫反彙編器)可以拆卸 是你最後的堆棧跟蹤,給你反饋哪個字節碼指令拋出最後一個未捕獲的異常。「
但有沒有這方面的解釋書中
所以,是否有人有想法上述模塊怎麼可能對調試有用嗎?
讀「每個程序員應該知道的97件事」我發現有關代碼分析工具的有趣文章。使用反彙編程序來調試錯誤Python
作者聲稱,從Python標準庫彙編器可以調試你的每一天代碼
這裏去非常有用: 「有一件事這個庫(Python標準庫反彙編器)可以拆卸 是你最後的堆棧跟蹤,給你反饋哪個字節碼指令拋出最後一個未捕獲的異常。「
但有沒有這方面的解釋書中
所以,是否有人有想法上述模塊怎麼可能對調試有用嗎?
儘管反彙編程序可以幫助您瞭解Python如何理解您編寫的內容,但它不是唯一的工具。還有其他工具也可以提供幫助。我們將看到其中一些可以一起工作。
所以這裏有一個小片的Python:
# Python bytecode 3.4 (3310)
# Disassembled from Python 3.4.2 (default, May 17 2015, 22:17:04)
# [GCC 4.8.2]
# Timestamp in code: 1499405520 (2017-07-07 01:32:00)
# Source code size mod 2**32: 39 bytes
# Method Name: <module>
# Filename: five.py
# Argument count: 0
# Kw-only arguments: 0
# Number of locals: 0
# Stack size: 2
# Flags: 0x00000040 (NOFREE)
# First Line: 1
# Constants:
# 0: <code object five at 0x7f99dd4e88a0, file "five.py", line 1>
# 1: 'five'
# 2: None
# Names:
# 0: five
# 1: print
1:
LOAD_CONST 0 (<code object five at 0x7f99dd4e88a0, file "five.py", line 1>)
LOAD_CONST 1 ('five')
MAKE_FUNCTION 0 (0 positional, 0 name and default, 0 annotations)
STORE_NAME 0 (five)
3:
LOAD_NAME 1 (print)
LOAD_NAME 0 (five)
CALL_FUNCTION 0 (0 positional, 0 keyword pair)
CALL_FUNCTION 1 (1 positional, 0 keyword pair)
POP_TOP
LOAD_CONST 2 (None)
RETURN_VALUE
...
(這是Python的:使用跨平臺的反彙編我寫這就是所謂xdis它的拆卸
def five():
return 5
print(five())
這裏部分3.4,其他版本略有不同)。
首先要注意的是python認爲這段代碼來自一個路徑名爲的文件。如果你碰巧重命名文件而不是Python代碼,這可能會混淆Python。或者文件名可能是tmp/five.py
,然後你應該找那個。此外,在Python版本3及更高版本中,文件的大小爲(模2 ** 32)作爲檢查以查看文件系統上的five.py
是否與編譯該文件時看到的一樣。
我將注意力放在代碼的開頭:我們正在加載一個常量對象,它恰好是函數的代碼!然後再輸入函數的名稱,最後調用MAKE_FUNCTION
並將其保存在一個名爲五個的變量中。
如果您習慣於像C++,Go或Java這樣的編譯語言,但不這樣做的事情有點不同尋常,那就是當您運行該程序時,該功能就是在當地創建的。如果我的節目之前有另外的指令,並分別改爲:
x = five() # five is hasn't been defined here!
def five(): ...
因爲該MAKE_FUNCTION尚未運行,因此在開始5尚未確定這將失敗。
現在,我還會建議你也許可以這樣使用調試器,以及和我再次trepan2或具有該裝配內置了一個命令,拆卸,甚至逆解析器trepan3建議學習。
反彙編可以闡明的另一個地方是Python對代碼進行優化的極少數情況。
考慮這個Python源代碼:
if 1:
y = 5
在這裏,Python版本後約2.3只會注意到if 1:
是多餘的,並刪除代碼。但是,如果你不得不說,而不是:
x = 1
if x:
y = 5
這足以混淆的Python,以保持在拆卸測試是我認爲你可以知道這一點的唯一方法。
最後一個方面,是正確理解其中當你在調試器中停止或出現錯誤時。你經常(但不是總是)弄清楚你有錯誤的路線,但有時候這可能會讓你感到困惑。正常 Python屏蔽了這裏很有用的信息,指令偏移量,但是我會告訴你如何得到這些信息以及指令在哪裏出錯。
假設我的代碼是:
prev = [100] + range(3)
x = prev[prev[prev[0]]]
如果我跑這我會得到一個IndexError例外。但是哪個「prev」是?
trepan2(或trepan3k)這裏暴露指令指針。它還可以訪問反彙編程序和解析程序。那麼讓我們來看看如何在這裏使用:
trepan2 /tmp/boom.py
-> 2 prev = [100] + range(3)
(trepan2) next
(/tmp/boom.py:3 @19): <module>
-- 3 x = prev[prev[prev[0]]]
(trepan2) next
(/tmp/boom.py:3 @32): <module>
!! 3 x = prev[prev[prev[0]]]
R=> (<type 'exceptions.IndexError'>, 'list index out of range', <traceback object at
(trepan2) info pc
PC offset is 32.
2 0 LOAD_CONST 0 100
3 BUILD_LIST 1
6 LOAD_NAME 0 0
9 LOAD_CONST 1 3
12 CALL_FUNCTION 1 1 positional, 0 keyword pair
15 BINARY_ADD None
16 STORE_NAME 1 1
3 19 LOAD_NAME 1 1
22 LOAD_NAME 1 1
25 LOAD_NAME 1 1
28 LOAD_CONST 2 0
31 BINARY_SUBSCR None
--> 32 BINARY_SUBSCR None
33 BINARY_SUBSCR None
34 STORE_NAME 2 2
37 LOAD_CONST 3 None
40 RETURN_VALUE None
好的。所以我們看到,其中正好是我們偏移32(@ 32之前在偏移@ 19處停止之後),但這是什麼意思?該環鋸將調試轉換回Python的這個,所以你不必自己做:
(trepan2) deparse -p
instruction: 32 BINARY_SUBSCR
x = prev[prev[prev[0]]]
-------------
Contained in...
Grammar Symbol: binary_subscr
x = prev[prev[prev[0]]]
-------------------
(trepan2) prev
[100, 0, 1, 2]
以上,那麼,說明你在偏移32(不是31或33)和特定上一頁訪問不是第一次訪問prev[0]
但後面的那個prev[prev[0]]
。
雖然在調試器內部同時具有disasembler和deparser,但它使您不必知道很多有關正在發生的事情。但我不認爲知道指令的作用或指令的順序是很痛苦的。
開始[這裏](https://docs.python.org/3/library/dis.html)。 – Kevin 2015-02-10 16:01:07
異常通常是數據問題的結果,而不是代碼。 – 2015-02-10 16:38:29