Python 代碼 Debug 的十個(gè)實(shí)用技巧
我們?nèi)粘懘a過程中,難免會(huì)寫出各類錯(cuò)誤,這些錯(cuò)誤可能是語法錯(cuò)誤、邏輯錯(cuò)誤或運(yùn)行時(shí)錯(cuò)誤。我們可以使用最復(fù)雜的答案是來檢測(cè)到錯(cuò)誤。也可以通過仔細(xì)閱讀回溯、使用調(diào)試工具、使用 linters 進(jìn)行靜態(tài)分析以及運(yùn)行測(cè)試來檢測(cè)錯(cuò)誤,確保在運(yùn)行之前和運(yùn)行期間識(shí)別問題。
1.使用print語句進(jìn)行調(diào)試
使用print語句進(jìn)行調(diào)試就像在你要去的路上放置路標(biāo),我個(gè)人在我的隱喻中相信這一點(diǎn)
就像路標(biāo)引導(dǎo)你并告訴你身在何處一樣,代碼中的打印語句會(huì)顯示變量的當(dāng)前值以及程序執(zhí)行到的位置。
通過檢查這些“路標(biāo)”,你可以確定自己是否走在正確的道路上或是否出了問題。
print(f"Hello, World!\n");
在代碼的關(guān)鍵點(diǎn)插入print()語句以輸出變量值并跟蹤執(zhí)行流程。這可以幫助你了解不同階段發(fā)生的情況。
例如:
我們?cè)谛兄惺褂昧藀rint語句作為路徑(代碼流)上的路標(biāo),告訴你你在哪里以及發(fā)生了什么。如果出現(xiàn)問題,你可以使用這些檢查點(diǎn)來找出路徑(代碼)將你引入歧途的地方。
def hiking_trip(start, destination):
print(f"從{start}開始徒步。") # 路標(biāo) 1
midpoint = (start + destination) / 2
print(f"到達(dá)中點(diǎn):{midpoint}.") # 路標(biāo) 2
if midpoint > 50:
print("The midpoint is quite far!") # 路標(biāo) 3
print(f"繼續(xù)前往目的地:{destination}.") # 路標(biāo) 4
return destination
hiking_trip(0, 100)
2.利用Python的內(nèi)置pdb模塊
使用 Python 的pdb模塊就像暫停電影并逐幀播放。
就像你可以暫停、倒帶或快進(jìn)電影來查看正在發(fā)生的事情一樣,pdb 可讓你隨時(shí)暫停代碼,檢查正在發(fā)生的事情,并一步一步地瀏覽代碼。這樣,你可以仔細(xì)檢查代碼的每個(gè)部分,以找出可能出錯(cuò)的地方。
使用該pdb模塊設(shè)置斷點(diǎn)并以交互方式逐步執(zhí)行代碼。首先插入import pdb; pdb.set_trace()要暫停執(zhí)行的位置。
命令
python -m pdb your_script.py
例如:
例如,通過添加pdb.set_trace()到你的程序中,執(zhí)行將在該行停止,從而允許你與提示符進(jìn)行交互pdb。一旦到達(dá)提示符。
import pdb
def example_function(x, y ):
result = x + y
pdb.set_trace() # 執(zhí)行將在此處暫停
print(f"結(jié)果是{result}")
return result
example_function(3, 5)
你可以使用各種命令來調(diào)試,例如:
n:轉(zhuǎn)到下一行代碼。s:進(jìn)入函數(shù)調(diào)用。c:繼續(xù)執(zhí)行,直到下一個(gè)斷點(diǎn)。
3.利用IDE調(diào)試器
使用 IDE 調(diào)試器就像在觀看電影時(shí)擁有一個(gè)具有高級(jí)功能的遙控器。
你可以暫停、跳過場(chǎng)景并查看幕后細(xì)節(jié),IDE 調(diào)試器可以讓你設(shè)置斷點(diǎn)、檢查變量并以可視化的方式控制代碼流程。
利用 PyCharm 或 VSCode 等 IDE 中的內(nèi)置調(diào)試器。這些工具提供了用于設(shè)置斷點(diǎn)、檢查變量和逐步執(zhí)行代碼的圖形界面。
例如:
在 PyCharm 或 VSCode 等 IDE 中調(diào)試程序時(shí),你可以在代碼中所需的關(guān)鍵點(diǎn)設(shè)置斷點(diǎn),類似于在重要場(chǎng)景暫停電影。隨時(shí)徹底檢查變量,就像看到電影幕后的細(xì)節(jié)一樣。一次執(zhí)行一行代碼,就像使用遙控器在電影中逐幀跳過一樣。
def movie_scene(start, end):
scene_duration = end - start # 這是代碼的“電影長(zhǎng)度”
important_event = start + scene_duration // 2 #“電影”的中點(diǎn)
return f"重要事件發(fā)生在{important_event}秒。"
movie_scene( 0 , 120 )
當(dāng)調(diào)試器暫停執(zhí)行時(shí),你將能夠執(zhí)行以下命令:
檢查start和end的值??纯磗cene_duration評(píng)估結(jié)果是什么。跨到下一行進(jìn)行計(jì)算important_event。
4.利用日志記錄獲取更好的洞察力
使用日志記錄而不是打印語句就像保存詳細(xì)的日記而不是便簽。
如果你需要快速記賬,可以使用打印語句,它可以像便簽一樣工作,便簽可以為你提供快速提醒,而日記(記錄)可以讓你記錄不同級(jí)別的細(xì)節(jié),從隨意的觀察到關(guān)鍵問題。
日志記錄稍微復(fù)雜一些。你可以根據(jù)日志的重要性查看它們,并調(diào)整要查看的詳細(xì)信息,從而幫助你更系統(tǒng)地跟蹤代碼中發(fā)生的情況。
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug('這是一條調(diào)試消息')
用 Python 的模塊替換print()語句logging。日志可以記錄不同級(jí)別的消息(DEBUG、INFO、WARNING、ERROR、CRITICAL),并控制顯示的詳細(xì)信息量。例如:
DEBUG:詳細(xì)信息,用于診斷問題。INFO:確認(rèn)一切如預(yù)期進(jìn)行。WARNING:表示發(fā)生了意外的事情,但是程序仍然在運(yùn)行。ERROR:更嚴(yán)重的問題,程序可能無法繼續(xù)運(yùn)行。CRITICAL:一個(gè)嚴(yán)重的問題,意味著該程序可能無法繼續(xù)運(yùn)行。
import logging
# 配置日志記錄以顯示所有級(jí)別
logstash.basicConfig(level=logging.DEBUG)
def hill_log ( start, destination ):
logstash.info(f"從{start}開始徒步到{destination}。") # 正常流程的 INFO 級(jí)別
midpoint = (start + destination) / 2
logstash.debug(f"中點(diǎn)在{midpoint}。") # 詳細(xì)信息的 DEBUG 級(jí)別
if midpoint > 50 :
logstash.warning("中點(diǎn)比預(yù)期的遠(yuǎn)!") # 潛在問題的 WARNING 級(jí)別
if destination - start > 100 :
logstash.error("這次徒步太長(zhǎng)了!") # 重大問題的錯(cuò)誤級(jí)別
if destination - start > 200 :
logstash.critical("不可能徒步!目的地太遠(yuǎn)!") # 嚴(yán)重問題的 CRITICAL 級(jí)別
return destination
hill_log(0, 250)
在此示例中,你可以看到每個(gè)日志級(jí)別如何更加井然有序,并幫助你根據(jù)重要性顯示信息,就像日記一樣,它能讓你理清自己的旅程。此外,它還能讓你隨時(shí)篩選或查看日志,print這比在代碼中到處寫語句(便簽)要強(qiáng)大得多。我強(qiáng)烈推薦初學(xué)者使用這個(gè)!
5.仔細(xì)檢查回溯
仔細(xì)檢查回溯就像跟著地圖去尋找你在徒步旅行中迷路的地方一樣。
地圖(回溯)顯示你所走的確切路徑,并突出顯示出錯(cuò)的地方。通過在地圖上仔細(xì)追溯你的步驟,你可以準(zhǔn)確地找出錯(cuò)誤發(fā)生的位置并了解導(dǎo)致錯(cuò)誤的原因,從而幫助你回到正軌。
仔細(xì)閱讀錯(cuò)誤消息的完整回溯。它們提供了有關(guān)錯(cuò)誤發(fā)生位置和原因的詳細(xì)信息,可幫助你查明問題所在。
Traceback(most recent call last):
File "example.py", line 8, in <module>
main()
File "example.py", line 5, in main
result = divide_numbers(x, y)
File "example.py", line 2, in divide_numbers
return a / b
ZeroDivisionError: division by zero
ZeroDivisionError: division by zero–– –– 實(shí)際的錯(cuò)誤信息。
6.使用try和except進(jìn)行錯(cuò)誤處理
使用try和except進(jìn)行錯(cuò)誤處理就像攀爬時(shí)佩戴安全帶。
安全帶(try 塊)允許你繼續(xù)攀爬(代碼執(zhí)行),但如果你滑倒(發(fā)生錯(cuò)誤),安全帶會(huì)抓住你(except 塊),防止跌落(程序崩潰)。這樣,你就可以安全地瀏覽代碼中的危險(xiǎn)部分,而不會(huì)突然停止一切。
將可能引發(fā)錯(cuò)誤的代碼包裝在try塊中,并使用except塊處理異常。這可以幫助你管理和理解錯(cuò)誤,而不會(huì)導(dǎo)致程序崩潰。
例子
try:
risky_code()
except Exception as e:
print(f"An error occurred: {e}")
7. 用類型檢查
就像在開始烹飪之前要檢查配料是否正確且數(shù)量正確一樣,類型檢查可在運(yùn)行代碼之前確保變量和函數(shù)具有正確的類型。這可以幫助你盡早發(fā)現(xiàn)潛在的混淆(類型相關(guān)錯(cuò)誤),防止問題在以后破壞你的程序。
使用類型提示和工具mypy執(zhí)行靜態(tài)類型檢查并在運(yùn)行之前捕獲類型相關(guān)的錯(cuò)誤。
命令
mypy your_script.py
8.使用斷言進(jìn)行測(cè)試
你使用斷言檢查代碼中的條件在特定點(diǎn)是否正確。如果某些東西看起來不自然,斷言會(huì)立即捕捉到它,幫助你發(fā)現(xiàn)并修復(fù)邏輯錯(cuò)誤,以免它們?cè)斐筛蟮膯栴}。
使用assert語句來驗(yàn)證代碼中各個(gè)點(diǎn)的條件是否成立。斷言可以幫助盡早發(fā)現(xiàn)邏輯錯(cuò)誤。
例子
assert x > 0, "x must be positive"
9.使用 Linters 分析代碼
使用 linters 分析代碼就像對(duì)你的寫作進(jìn)行語法檢查一樣。
就像語法檢查器會(huì)突出顯示文本中的錯(cuò)誤、不恰當(dāng)?shù)拇朕o和風(fēng)格問題一樣,
linter 會(huì)掃描你的代碼,查找語法錯(cuò)誤、 編碼風(fēng)格違規(guī)和潛在錯(cuò)誤。這有助于你清理代碼,使其更易讀、更一致且無錯(cuò)誤。
使用 pylint 或 flake8 等 linters來捕捉語法錯(cuò)誤、文體問題和潛在錯(cuò)誤。
命令:pylint your_script.py
10. 使用代碼分析器進(jìn)行監(jiān)控
使用代碼分析器就像使用健身追蹤器來監(jiān)控你的鍛煉一樣。
為什么我要對(duì)健身追蹤器說這些,因?yàn)榫拖窠∩碜粉櫰骺梢詼y(cè)量你的表現(xiàn),識(shí)別需要改進(jìn)的地方,并在需要時(shí)為你提供指導(dǎo)一樣,代碼分析器也可以跟蹤同樣的工作。你的程序如何運(yùn)行并突出顯示其運(yùn)行速度變慢或遇到問題的地方。這有助于你優(yōu)化代碼并提高其效率。
使用分析工具cProfile來測(cè)量代碼的性能并識(shí)別可能導(dǎo)致意外行為的瓶頸或區(qū)域。
命令:python -m cProfile your_script.py
寫在最后
在本文中,我們探討了識(shí)別代碼或項(xiàng)目中的錯(cuò)誤的各種方法和做法。無論你是初學(xué)者還是大佬級(jí),這些技巧對(duì)于發(fā)現(xiàn)錯(cuò)誤都非常有用。我們介紹了十種不同的技巧,每種技巧都用簡(jiǎn)單的類比來解釋,以幫助你掌握基礎(chǔ)知識(shí)。