程式碼除錯
問題闡述
最近遇到一個python debug多程序的問題
有一個程序A,這個程序會fork出8個程序B,fork join結束後,又會fork出8個程序A。
假設按時間有序,我就只想斷fork出的第一個B和第一個程序A,怎麼做?(breakpoint just break only once)
類似於java多執行緒除錯的意思,只斷一個執行緒,all->thread,make default
斷點命中時不會阻塞其他程序
https://blog.csdn.net/u011781521/article/details/79251819
主要幾個問題點
- 多個程序會同時刷log,特別亂,沒辦法過濾(加pid過濾,還算好解決)
- 使用pdb斷點時,會同時block所有其他程序
除錯主流方式
首先python主流有兩類debug方式
第一類是透過ide,比如vscode、pycharm。
比較無腦、介面化的操作方式,但缺點也很明顯,很依賴一個可以控制的函式入口(例如main,ut入口)。
第二類是透過pdb,在相關程式碼片段中加breakpoint語句,等程序執行時自動觸發斷點,進行攔截。
適合一些比較複雜的程序衍生模式,不太依賴特定的函式入口。這種相對來說更精確一點,對依賴外部環境依賴小。
需要對pdb、gdb類似的東西有一定的瞭解。其次,多程序下並不太友好;pdb本身功能過於單一。
找了一下pdb的平替有pdb++、ipdb、rpdb。
rpdb就是remote,前兩個其實差不多,但是pdb的好處是,基本你不需要去改原來的pdb斷點,開箱即用。
pdb++還有啥好處見引文,但是還是存在多程序不友好的問題,會多次觸發斷點,一個命令語句會有較多的副作用,尤其在Smart command parsing加持下,基本就是不可除錯的狀態。
TL; DR
pdbpp
(又稱pdb++
)是 Python 標準偵錯程式pdb
的一個增強版本,為除錯體驗提供了許多改進和新功能。在功能上,它完全向後相容pdb
,但增加了許多便利的特性,簡化了除錯過程。以下是pdbpp
相比於pdb
提供的主要增強功能:1. 彩色語法高亮(Syntax Highlighting)
pdbpp
使用pygments
庫為程式碼和輸出提供彩色語法高亮顯示,使得偵錯程式輸出更加易讀,特別是在檢視複雜表示式和程式碼塊時。變數名、關鍵字、字串、數字等會有不同的顏色,幫助使用者快速定位資訊。
- pdb:沒有顏色,輸出是純文字。
- pdbpp:提供語法高亮,顏色區分不同型別的內容。
2. 更強大的自動補全(Tab Completion)
在
pdbpp
中,按下Tab
鍵可以自動補全變數名、函式名、類名等,類似於現代 IDE 中的補全功能。這大大提高了除錯時的效率,特別是在處理複雜的物件或長命名時。
- pdb:有限的自動補全功能。
- pdbpp:增強的自動補全,支援更多命令、變數、物件屬性和方法。
3. 可配置的顯示選項(Sticky Mode)
pdbpp
提供一個非常強大的 "sticky mode",它可以在除錯過程中始終顯示當前程式碼的上下文。每次執行下一步時,pdbpp
會自動重新整理並顯示當前程式碼段的最新狀態,而不需要手動檢視程式碼上下文。
- pdb:手動使用
list
或longlist
檢視程式碼上下文。- pdbpp:
sticky mode
持續顯示程式碼上下文,使用者更容易跟蹤執行的程式碼。4. 更智慧的除錯命令
pdbpp
增強了原始pdb
的一些常用命令,並增加了新的命令:
interact
:允許你在偵錯程式中啟動一個互動式 Python shell,直接操作除錯時的上下文和變數。longlist
(ll
):顯示當前函式的完整程式碼,而不僅僅是當前行的上下文。sticky
:啟用或禁用sticky mode
,在該模式下會持續顯示程式碼的上下文。track
:跟蹤異常,並顯示其完整的追溯資訊。source
:檢視某個函式或方法的完整原始碼。5. 更靈活的配置和擴充套件
pdbpp
提供了更多的配置選項,允許你透過.pdbrc
檔案自定義偵錯程式的行為,例如顏色、補全方式、命令別名等。
- pdb:有限的配置選項。
- pdbpp:支援使用者自定義配置檔案,靈活設定偵錯程式的行為。
6. 更好的 Python 3 支援
pdbpp
針對 Python 3 做了更多最佳化,支援 Python 3 的新語法和特性,如async
和await
,並能更好地處理 Python 3 中的一些新特性。7. 友好的錯誤資訊
pdbpp
提供了更加直觀的錯誤資訊格式,增強了顯示異常和回溯的方式,使除錯複雜的錯誤更加容易。8. 可自定義的偵錯程式提示符
你可以透過
pdbpp
自定義偵錯程式的提示符(prompt)。這對某些開發者來說是個很方便的功能,特別是當你在長時間除錯時,能夠清楚知道當前的除錯狀態。9. 顯示變數值的懸停功能
當你在
pdbpp
中檢視程式碼時,懸停在變數上會顯示其當前的值。這對於快速檢視變數的狀態非常有用,無需輸入變數名來檢視當前值。
小結
pdbpp
是pdb
的一個增強版本,帶來了彩色高亮、自動補全、sticky mode
、自定義配置等功能,大大提升了除錯體驗。如果你經常使用pdb
進行除錯,pdbpp
將讓你的除錯過程更高效、愉快。
問題場景
現在我往我關心的程式碼裡,加入了斷點import pdb; pdb.set_trace()
,但是他連續觸發了8次,導致我沒辦法繼續除錯了,怎麼辦?
按了一次c直接所有其他程序都相應,我有沒有辦法只斷某一個程序(隨便哪個)?
比較直覺的會想到條件斷點,但是觸發條件的唯一值有哪些呢?
方案思路
天然唯一值,比如pid、ppid、deviceid、特定配置引數,process相關引數,持有的一些特殊資源(fd描述符)。
非天然唯一值,比如特定環境變數。
也可以考慮鎖,誰先搶佔到鎖,誰就一直持有這把鎖(至少能保證只有一個程序斷到),這個可以往一個特定檔案寫入pid實現。封裝一個get函式,這個函式嘗試讀取一個檔案,如果這個檔案不存在,先建立並寫入當前的程序id,再返回該id,如果這個檔案存在,直接返回檔案內容轉成int,上層只需要比較id和自身os.getpid()的一致性。
方案細節
方案A 判斷ppid
由於最開始只有一個父程序,所以用他作為ppid去判定。然而並不正確,子程序fork了8個,8個同時命中無效。
方案B 判斷pid
pid對10取餘,用一個magic number(比如0),判斷相等性,進行斷點。
(有效且粗暴的方式,但具有一定隨機性。這塊是由於程序pid的分配演算法,程序pid並不一定具有連續性,並且有一定隨機性,有可能出現無法命中或者多次命中的機率。)
方案C 父程序傳變數給子程序
只需要在子程序fork一開始傳入一個唯一值即可,這裡用到了環境變數。
首先最開始的父程序A程序是一個前臺程序,ctrl+c打斷時,會觸發一些multiprocessing和task相關的堆疊,其實可能A在執行過程中fork了其他所有程序(事實上並不對)。
嘗試檢索了一下相關庫,檢索multiprocessing關鍵字,確實能找到一句
ctx = multiprocessing.get_context("spawn")
...
for i in range(5):
item = ctx.Process(...)
item.start()
...
嘗試在loop中,先設定os.environ['DEBUG']=i
,fork出來的子程序會繼承(unix機制,子程序會繼承父程序的一些屬性)環境變數,嘗試用該環境變數做判斷,發現斷點斷不上,這個方案是有問題的。
原因是父程序A fork出了8個B,我們關心的斷點其實在B的程序中,fork完8個B程序,父程序A完成join,繼續開始fork8個A子程序,理論上這些斷點會生效,但是我們miss掉了斷點出現的時機。
方案D 父程序B讀取一些特定配置值(比如deviceid 0-8)做判斷
D.A 嘗試讀取一個config值裡的特定欄位,但發現這個config是動態生成的,他也不是一個單例(python中的單例不太一樣,強行弄意義不大),並且這個值載入的時機不明確,所以不能用
D.B 嘗試獲取該程序持有的一些資源、檔案描述符(如/dev/xxx),感覺有點麻煩,但是理論上是可行的
D.C 透過ps -ef
觀察,其實程序B在啟動時有一些特定的唯一值入參,程序的啟動命令大概長process_b device_id 8 deivce_id xxxx
,能明顯看出,第二個引數就是我們需要的唯一值。
嘗試透過sys.argv獲取第一個引數,直接判斷。發現sys.argv竟然是空的,那麼這些引數來自哪裡呢?
只有透過python命令列啟動的程序,才會有sys.argv,如果不是這種方式,比如用c啟動的命令列,他就不會有這個引數。
那如何獲取這個引數?
兩種方式,第一種取讀取/proc/{pid}/cmdline
下的一些屬性,找到這個值,第二種
import psutil
p = psutil.Process()
cmdline = p.cmdline()
採用了第二種方式,再pdb++獲取了cmdline[1],並且和'1'比較測試了一下,是成功的。至此,完成了條件斷點。
小結
- 要注意觀察程序的建立方式和建立的流程(ps -ef, pstree)
- 明確需要斷點問題的界限
- 尋找一切與問題相關的上下文,儘可能將問題縮小在一個區間
TL;DR
程式碼閱讀&修改
container內python程式碼除錯
現在的ide普遍都支援ssh連線,理論上只要配置好了ssh服務,就可以直接連container,直接對container內的程式碼進行除錯。(直接用開發機的開發機環境是最好的,程式碼可以隨意點,都不會報錯和飄紅)
ssh
安裝ssh服務(能用apt直接安的可以省這一步)
- 從網站隨意下一下原始碼包
https://www.openssh.com/portable.html
- 解壓進入到程式碼目錄
- ./configure 生成編譯需要的配置檔案
- make $(nproc) 編譯
- make install 安裝
配置
vim /etc/sshd/sshd_config
PermitRootLogin改成yes,password-auth也改成yes,埠隨便換一個,不要和宿主機撞
啟動
service ssh start
(這塊不能用systemctl)
宿主機要把docker這個埠主動的暴露出去(這個在啟動的時候就要完成)
pycharm ssh配置連線
包太大,下載不了的問題參考
https://blog.csdn.net/qq_42534403/article/details/135969955
連線完效果大概像
基本和本地開發效果一致,比較惱火的是,他有時候不會儲存專案開啟前後的上下文,可能你做的一些mark或者pin都會丟失。
如果對library進行除錯,額外注意需要標註
pdb++ cheatsheet (via gpt4)
個人感覺比較好用的就是ll pp sticky,最好禁用Smart command parsing(真是自作聰明的行為),基本用著和解釋性語言的感覺差不多,像是直接在python中執行一樣
下面是一個方便參考的
pdb++
除錯命令 Cheatsheet,它包含了pdb++
中常用的除錯命令以及增強功能,幫助你快速上手除錯。
pdb++ Cheatsheet
基本命令
命令 說明 h
/help
顯示幫助資訊,輸入 help <command>
檢視某個命令的詳細幫助。n
/next
執行下一行程式碼,跳過函式呼叫。 s
/step
進入下一行程式碼,如果是函式呼叫,則進入函式內部。 r
/return
執行到當前函式的返回處。 c
/continue
繼續執行程式,直到遇到下一個斷點。 q
/quit
退出偵錯程式,終止程式。 l
/list
顯示當前程式碼的上下文(預設 11 行),可指定範圍,如 list 10, 20
。ll
/longlist
顯示當前函式的完整程式碼。 p
/列印表示式的值,例如 p my_var
。pp
使用漂亮的格式(pretty print)列印表示式的值。 w
/where
顯示當前的呼叫棧資訊。 bt
同 where
,顯示完整的回溯資訊。up
/u
移動到上一層呼叫棧。 down
/d
移動到下一層呼叫棧。
斷點管理
命令 說明 b
/break
設定斷點。用法: break <lineno>
或break <filename>:<lineno>
。tbreak
設定臨時斷點,命中一次後自動刪除。 cl
/clear
清除所有斷點。 disable
禁用斷點。 enable
啟用斷點。 ignore
忽略斷點,指定命中多少次後才啟用。 condition
為斷點設定條件。例如: condition 1 x > 10
。
變數和表示式
命令 說明 p
/列印表示式的值,例如 p my_var
。pp
使用漂亮的格式(pretty print)列印表示式的值。 whatis
顯示錶達式的型別,例如 whatis my_var
。display
每次停止時自動顯示一個表示式的值,例如 display my_var
。undisplay
取消顯示某個表示式的值。 a
/args
列印當前函式的引數及其值。 retval
顯示最後一個返回值。 locals()
檢視當前作用域中的區域性變數。 globals()
檢視全域性變數。
程式碼執行
命令 說明 !
執行 Python 表示式。例如 !my_var = 5
。interact
啟動一個互動式 Python shell,可以在當前上下文中執行任意程式碼。 run
重新執行指令碼。例如: run arg1 arg2
。
特殊功能
命令 說明 sticky
啟用/禁用 粘性模式,在除錯時持續顯示程式碼上下文。 source
顯示某個函式或類的原始碼,例如 source my_function
。track
跟蹤異常,顯示其完整的追溯資訊。 display
在每次停止時自動顯示指定的變數值。 undisplay
停止自動顯示變數值。
粘性模式(Sticky Mode)
sticky
模式是pdb++
中的一個特殊功能,它會在除錯時持續顯示當前程式碼的上下文。每次程式執行到下一行,pdb++
會自動重新整理並顯示當前位置的程式碼片段。
啟用/禁用:
- 輸入
sticky
切換模式。使用場景:
- 在除錯過程中,
sticky
模式可以幫助你持續觀察程式碼的變化,無需手動呼叫list
命令。
命令別名
pdb++
允許你為常用命令建立別名,簡化除錯過程。例如,你可以為longlist
建立一個別名ll
。alias ll longlist
你也可以在
.pdbrc.py
檔案中配置這些別名,以便每次啟動pdb++
時自動載入。
自定義配置
你可以透過
~/.pdbrc.py
檔案自定義pdb++
的行為,例如自動啟用語法高亮、粘性模式、設定別名等。示例
.pdbrc.py
檔案:# ~/.pdbrc.py # 自動啟用粘性模式 def setup(self): self.sticky = True # 設定別名 alias ll longlist alias n next alias s step alias c continue
除錯快捷鍵
快捷鍵 說明 Ctrl + D
退出偵錯程式。 Ctrl + L
清屏。 Tab
自動補全命令、變數、函式名等。
常用除錯工作流
- 啟動除錯:在程式碼中插入
import pdb; pdb.set_trace()
,或者執行指令碼時透過python -m pdb your_script.py
進入除錯模式。- 設定斷點:用
break <lineno>
或tbreak
設定斷點。- 逐步除錯:使用
next
或step
逐行執行程式碼,檢查變數的值。- 檢查變數:透過
p
或pp
列印變數的值,使用whatis
檢視變數的型別。- 跟蹤異常:使用
track
追蹤異常的完整回溯資訊。- 使用粘性模式:透過
sticky
持續顯示程式碼的上下文,實時跟蹤程式碼執行。
結語
pdb++
是一個強大且靈活的除錯工具,它在pdb
的基礎上提供了許多增強功能,使除錯過程更加高效、直觀。透過這份 Cheatsheet,你可以快速掌握pdb++
的常用命令並提升除錯效率。
pdb(pdb++)方法
下面是你列出的
pdb++
(和pdb
)中常用函式的詳細講解,包括各個函式的簽名、引數說明、用法以及它們的具體作用。在pdb++
中,這些函式提供了靈活的除錯能力,可以根據具體需求使用不同的除錯方法。
1.
pdb.run(statement, globals=None, locals=None)
作用
- 在偵錯程式中執行一條 Python 語句(類似於
exec()
函式),並在執行該語句時進入除錯模式。簽名
def run(statement: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> None
引數
statement
: 一個字串型別的 Python 語句,表示你想要執行的程式碼。globals
: 可選引數,表示全域性名稱空間的字典。如果不提供,預設為None
,使用當前的全域性名稱空間。locals
: 可選引數,表示區域性名稱空間的對映。如果不提供,預設為None
,使用當前的區域性名稱空間。用法
import pdb statement = 'x = 10; y = 20; z = x + y' pdb.run(statement)
說明
pdb.run()
類似於exec()
,但在執行過程中啟動偵錯程式,方便你除錯一段程式碼的執行過程。
2.
pdb.runeval(expression, globals=None, locals=None)
作用
- 在偵錯程式中求值一個表示式(類似於
eval()
函式),並返回其結果。這個函式允許你在除錯模式下執行表示式並獲取結果。簽名
def runeval(expression: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> Any
引數
expression
: 一個字串型別的 Python 表示式,表示你想要計算的表示式。globals
: 可選引數,表示全域性名稱空間的字典。如果不提供,預設為None
,使用當前的全域性名稱空間。locals
: 可選引數,表示區域性名稱空間的對映。如果不提供,預設為None
,使用當前的區域性名稱空間。用法
import pdb expression = '10 + 20' result = pdb.runeval(expression) print(result)
說明
pdb.runeval()
類似於eval()
,但在偵錯程式執行環境中執行表示式,並返回計算結果。
3.
pdb.runctx(statement, globals, locals)
作用
- 在偵錯程式中執行一條 Python 語句,並顯式傳遞全域性和區域性名稱空間。這與
pdb.run()
類似,但強制要求提供globals
和locals
引數。簽名
def runctx(statement: str, globals: dict[str, Any], locals: Mapping[str, Any]) -> None
引數
statement
: 需要執行的 Python 語句。globals
: 全域性名稱空間的字典。locals
: 區域性名稱空間的對映。用法
import pdb globals = {'a': 10} locals = {'b': 20} statement = 'c = a + b' pdb.runctx(statement, globals, locals) print(globals, locals)
說明
pdb.runctx()
允許你使用自定義的名稱空間執行程式碼,這在除錯複雜的上下文時非常有用。
4.
pdb.runcall(func, *args, **kwds)
作用
- 在偵錯程式中呼叫一個函式,並傳遞引數。這允許你在除錯模式下執行函式並檢查其執行過程。
簽名
def runcall(func: Callable[_P, _T], *args: _P.args, **kwds: _P.kwargs) -> _T | None
引數
func
: 要呼叫的函式。*args
: 傳遞給函式的引數。**kwds
: 傳遞給函式的關鍵字引數。用法
import pdb def divide(a, b): return a / b result = pdb.runcall(divide, 10, 2) # 除錯 divide(10, 2) print(result)
說明
pdb.runcall()
允許你在偵錯程式中執行某些函式,並檢查函式執行的每一步。這在除錯有引數的函式時非常有用。
5.
pdb.set_trace()
作用
- 手動在程式碼中設定一個斷點,啟動偵錯程式並暫停程式執行。
簽名
def set_trace(*, header: str | None = None) -> None
引數
header
: 可選引數,型別為str | None
,表示當偵錯程式啟動時輸出的自定義訊息。如果不提供,預設為None
。用法
import pdb def my_function(): x = 10 pdb.set_trace(header="偵錯程式啟動") # 在這裡進入除錯模式,顯示自定義訊息 y = 20 z = x + y print(z) my_function()
說明
pdb.set_trace()
是手動除錯的常用工具,它允許你在程式碼執行到某個位置時暫停,並進入除錯模式。header
引數可以提供額外的資訊,以便在偵錯程式啟動時顯示。
6.
pdb.post_mortem()
作用
- 在異常發生後啟動偵錯程式,允許你檢視異常發生時的上下文。這在除錯未捕獲的錯誤時非常有用。
簽名
def post_mortem(t: TracebackType | None = None) -> None
引數
t
: 可選引數,型別為TracebackType | None
,表示要除錯的回溯物件。如果不提供,使用最近的異常回溯。用法
import pdb def divide(a, b): return a / b try: divide(1, 0) except ZeroDivisionError: pdb.post_mortem() # 在異常發生後進入除錯模式
說明
post_mortem()
允許你在異常發生後進入偵錯程式,並檢查導致異常的上下文。在除錯程式崩潰時非常有用。
7.
pdb.pm()
作用
- 立即進入除錯模式,除錯最近的未捕獲異常。它是
post_mortem()
函式的快捷方式。簽名
def pm() -> None
引數
- 無引數。
用法
import pdb def divide(a, b): return a / b try: divide(1, 0) except: pdb.pm() # 除錯最近的未捕獲異常
說明
pm()
是post_mortem()
的簡化版本,自動處理最近發生的異常並啟動偵錯程式。它適合快速進入除錯模式,而無需顯式捕獲異常。
總結
run()
: 在除錯模式下執行一條 Python 語句。runeval()
: 在除錯模式下求值一個表示式並返回結果。runctx()
: 在除錯模式下執行一條 Python 語句,並使用自定義的全域性和區域性名稱空間。runcall()
: 透過偵錯程式呼叫一個函式,並傳遞引數。set_trace()
: 手動設定斷點,進入除錯模式。post_mortem()
: 在異常發生後進入除錯模式。pm()
: 除錯最近的未捕獲異常,是post_mortem()
的快捷方式。這些函式提供了靈活的除錯工具集,適合不同的除錯需求。
python debug相關環境變數
在 Python 中,偵錯程式(如
pdb
和pdb++
)可以透過一些環境變數進行配置和控制。這些環境變數可以影響偵錯程式的行為、設定以及輸出。以下是與 Python 除錯相關的主要環境變數:
1.
PYTHONBREAKPOINT
作用:控制程式中斷點的行為,特別是用於設定或禁用偵錯程式。
用法:
- 預設值:
PYTHONBREAKPOINT=pdb.set_trace
- 禁用斷點:將變數設定為
0
,所有的breakpoint()
呼叫將被忽略。- 自定義行為:你可以將其設定為任意可呼叫的除錯函式,甚至是自定義函式。
示例:
export PYTHONBREAKPOINT=0 # 禁用所有斷點 export PYTHONBREAKPOINT=my_debugger.set_trace # 使用自定義偵錯程式
說明:
- 在 Python 3.7+ 中,
breakpoint()
是用於手動進入除錯的內建函式。透過設定PYTHONBREAKPOINT
,你可以更改breakpoint()
的行為。- 如果設定為
0
,則除錯功能被禁用,即所有breakpoint()
呼叫將被忽略。
2.
PYTHONWARNINGS
作用:控制 Python 警告的顯示方式,通常用於除錯時檢視潛在問題。
用法:
- 預設值:Python 預設只顯示一次警告。
- 可以設定成
error
來將警告變為異常,這樣在偵錯程式中可以捕獲並除錯警告。格式:
PYTHONWARNINGS=action:message:category:module:line
(其中,action
是最常用的部分)常見值:
default
:預設行為,顯示一次警告。always
:總是顯示警告。ignore
:忽略警告。error
:將警告轉換為異常。module
:每個模組顯示一次警告。once
:僅顯示一次警告。示例:
export PYTHONWARNINGS="error" # 將所有警告視為錯誤 export PYTHONWARNINGS="always" # 總是顯示所有警告
說明:
- 當你設定
PYTHONWARNINGS="error"
時,所有 Python 警告將作為異常丟擲,這樣你可以在偵錯程式中捕獲它們並檢視具體的堆疊資訊。- 這在除錯潛在的程式碼問題或需要嚴格處理警告時非常有用。
3.
PYTHONTRACEMALLOC
作用:啟用或禁用記憶體分配跟蹤,用於除錯記憶體洩漏問題。
用法:
- 預設值:未啟用。
- 設定為正整數值來控制分配追蹤的深度。
示例:
export PYTHONTRACEMALLOC=1 # 啟用記憶體分配跟蹤,深度為 1 export PYTHONTRACEMALLOC=5 # 啟用記憶體分配跟蹤,深度為 5
說明:
- 啟用記憶體跟蹤後,Python 將記錄記憶體分配的堆疊資訊。這對於除錯記憶體洩漏或定位高記憶體使用問題非常有幫助。
- 你可以使用
tracemalloc
模組來獲取和顯示記憶體分配的相關資訊。
4.
PYTHONDEBUG
作用:啟用 Python 直譯器的除錯輸出,由直譯器在啟動時使用。
用法:
- 設定為任意非空值時,啟用除錯模式(直譯器的除錯資訊將輸出到標準錯誤流)。
示例:
export PYTHONDEBUG=1 # 啟用直譯器的除錯模式
說明:
- 啟用
PYTHONDEBUG
後,Python 會輸出更多的除錯資訊,包括一些內部機制的輸出內容。這對於除錯 Python 直譯器本身或者檢視直譯器的詳細執行資訊非常有用。
5.
PYTHONVERBOSE
作用:啟用詳細輸出模式,用於顯示 Python 直譯器載入模組的詳細資訊,適合除錯模組匯入問題。
用法:
- 設定為任意非空值時,啟用詳細模式。
示例:
export PYTHONVERBOSE=1 # 啟用詳細輸出模式
說明:
- 啟用
PYTHONVERBOSE
後,Python 會在程式執行過程中輸出每個模組匯入的詳細資訊。這對除錯模組匯入路徑、匯入衝突或未找到模組的問題非常有幫助。
6.
PYTHONMALLOC
作用:控制 Python 的記憶體分配器型別,用於除錯記憶體分配和記憶體問題。
可選值:
malloc
:使用系統的malloc()
。pymalloc
:使用 Python 的小物件分配器(預設)。debug
:使用 Python 的小物件分配器,並啟用記憶體除錯。示例:
export PYTHONMALLOC=debug # 啟用記憶體除錯
說明:
- 設定為
debug
時,Python 會啟用記憶體分配除錯機制,幫助你發現記憶體分配錯誤或記憶體洩漏問題。
7.
PYTHONFAULTHANDLER
作用:啟用 Python 的故障處理程式,使得 Python 在崩潰時列印出詳細的堆疊資訊。
用法:
- 設定為任意非空值,啟用故障處理程式。
示例:
export PYTHONFAULTHANDLER=1 # 啟用故障處理程式
說明:
- 啟用
PYTHONFAULTHANDLER
後,當 Python 崩潰時,它會列印出 Python 錯誤堆疊資訊,幫助你更容易地定位問題。特別是在除錯 C 擴充套件模組或者直譯器崩潰時非常有用。
8.
PYTHONHASHSEED
作用:控制字串和其他雜湊種子的初始化值。
用法:
- 設定為一個整數值,用於確定 Python 的雜湊種子。
- 隨機雜湊種子預設用於防止雜湊衝突攻擊,但在某些情況下(如除錯或測試),你可能希望使用固定值。
示例:
export PYTHONHASHSEED=42 # 使用固定的雜湊種子
說明:
- 在除錯涉及雜湊的程式碼(如字典、集合)時,使用固定的雜湊種子可以幫助你復現和除錯某些雜湊相關的錯誤。
9.
PYTHONINSPECT
作用:在程式執行結束後自動進入互動模式(REPL),可用於除錯。
用法:
- 設定為任意非空值時,程式執行結束後進入互動模式。
示例:
export PYTHONINSPECT=1 # 程式結束後進入互動模式
說明:
- 啟用
PYTHONINSPECT
後,當 Python 程式執行結束時,它會啟動互動式直譯器(REPL)。這在你想要在程式結束後進一步檢查狀態時非常有用。
總結
以下是常見的與 Python 除錯相關的環境變數:
PYTHONBREAKPOINT
:控制breakpoint()
的行為。PYTHONWARNINGS
:控制警告的處理方式。PYTHONTRACEMALLOC
:啟用記憶體分配跟蹤。PYTHONDEBUG
:啟用直譯器除錯模式。PYTHONVERBOSE
:啟用詳細輸出模式,除錯模組匯入問題。PYTHONMALLOC
:控制 Python 的記憶體分配器。PYTHONFAULTHANDLER
:啟用故障處理程式,捕獲崩潰時的堆疊資訊。PYTHONHASHSEED
:設定固定的雜湊種子,除錯雜湊相關問題。PYTHONINSPECT
:程式執行結束後進入互動模式。這些環境變數為開發者提供了靈活的除錯選項,適用於不同的除錯場景和除錯需求。
注意
breakpoint()
和set_trace()
有一些細小差別。