在Linux下調(diào)試Python代碼的各種方法
這是一個(gè)我用于調(diào)試或分析工具概述,不一定是完整全面,如果你知道更好的工具,請(qǐng)?jiān)谠u(píng)論處標(biāo)記。
日志
是的,的確,不得不強(qiáng)調(diào)足夠的日志記錄對(duì)應(yīng)用程序是多么的重要。您應(yīng)該記錄重要的東西,如果你的記錄足夠好的話,你可以從日志中找出問題從而節(jié)省大量的時(shí)間。
如果你曾經(jīng)用print語句來調(diào)試代碼現(xiàn)在停下吧,用logging.debug替代,開始可以慢慢來,以后完全禁用它...
追蹤
有時(shí)看到程序如何被執(zhí)行會(huì)很有幫助。你可以使用IDE的調(diào)試共軛ngn一步一步的運(yùn)行程序,但你需要知道你要找的是什么,否則這將會(huì)是一個(gè)漫長(zhǎng)的過程。
標(biāo)準(zhǔn)庫中有一個(gè) trace模塊,可以打印所有執(zhí)行過程中的內(nèi)容(像制作 覆蓋率報(bào)告)。
python -mtrace --trace script.py
這將產(chǎn)生大量輸出(每個(gè)行會(huì)被打印輸出,所以你最好通過管道,用grep只看自己感興趣的部分),例如:
python -mtrace --trace script.py | egrep '^(mod1.py|mod2.py)' -
如果你喜歡新特性,那么你可以嘗試 smiley - 它可以顯示變量?jī)?nèi)容變化,還可以用它來遠(yuǎn)程追蹤程序。
PDB
import pdb pdb.set_trace() # opens up pdb prompt
或者:
try: code that fails except: import pdb pdb.pm() # or pdb.post_mortem()
或(按鍵盤C鍵啟動(dòng)腳本):
python -mpdb script.py
像在REPL中那樣:
- c or continue
- q or quit
- l or list, 在當(dāng)前界面顯示源碼
- w or where, 顯示回溯
- d or down, 顯示回溯的下一界面
- u or up, 顯示回溯的上一界面
- <enter>, 重復(fù)最后一個(gè)命令
- 其他任何東西,在當(dāng)前界面評(píng)估源碼 (t還有其他的一些命令)
- corcontinue
- qorquit
- lorlist,顯示在當(dāng)前幀的源
- worwhere,顯示回溯
- dordown,下山1幀回溯
- uorup,上升1幀回溯
- 回車,重復(fù)最后一個(gè)命令
幾乎任何東西,評(píng)估當(dāng)前幀的Python代碼(還有其他幾個(gè)命令)
可以替代pdb的:
- ipdb (easy_install ipdb) - 像 ipython (自動(dòng)補(bǔ)齊, 顏色等)
- pudb (easy_install pudb) - 基于curses (類gui), 瀏覽源碼有很好的表現(xiàn)。
遠(yuǎn)程 PDB
sudo apt-get install winpdb
替代 pdb.set_trace():
import rpdb2 rpdb2.start_embedded_debugger("secretpassword")
現(xiàn)在運(yùn)行Winpdb , 輸入密碼 到 File > Attach。
不喜歡 Winpdb ? 只要通過 TCP運(yùn)行 PDB
使用下面代碼:
import loggging class Rdb(pdb.Pdb): """ This will run pdb as a ephemeral telnet service. Once you connect no one else can connect. On construction this object will block execution till a client has connected. Based on https://github.com/tamentis/rpdb I think ... To use this:: Rdb(4444).set_trace() Then run: telnet 127.0.0.1 4444 """ def __init__(self, port=0): self.old_stdout = sys.stdout self.old_stdin = sys.stdin self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.listen_socket.bind(('0.0.0.0', port)) if not port: logging.critical("PDB remote session open on: %s", self.listen_socket.getsockname()) print >> sys.__stderr__, "PDB remote session open on:", self.listen_socket.getsockname() sys.stderr.flush() self.listen_socket.listen(1) self.connected_socket, address = self.listen_socket.accept() self.handle = self.connected_socket.makefile('rw') pdb.Pdb.__init__(self, completekey='tab', stdin=self.handle, stdout=self.handle) sys.stdout = sys.stdin = self.handle def do_continue(self, arg): sys.stdout = self.old_stdout sys.stdin = self.old_stdin self.handle.close() self.connected_socket.close() self.listen_socket.close() self.set_continue() return 1 do_c = do_cont = do_continue def set_trace(): """ Opens a remote PDB on first available port. """ rdb = Rdb() rdb.set_trace()
想要 REPL ? IPython 怎么樣?
如果你不需要一個(gè)整體的調(diào)試器,只要啟動(dòng)IPython用下面的代碼:
import IPython IPython.embed()
標(biāo)準(zhǔn)Linux工具
他們未被充分利用很令我驚訝。通過這些工具集你能弄清楚諸如這些的很多問題:從性能問題(太多的系統(tǒng)調(diào)用,內(nèi)存分配等)到死鎖,網(wǎng)絡(luò),磁盤等問題。
sudo apt-get install htop sudo htop
最有用的是降權(quán)運(yùn)行strace,只需運(yùn)行速凍 strace -P 12345 或strace-f 命令參數(shù)(-f表示strace分支進(jìn)程)。 通常有很多的輸出,你最好將輸出重定向輸出到一個(gè)文件(命令后添加 &> 文件名)來進(jìn)行更深入的分析。
然后就是ltrace,它和strace相似不過是通過庫調(diào)用的,參數(shù)基本相同。
lsof可以提供 你看過ltrace/ strace的處理號(hào),這樣使用:lsof -P 12345
讓跟蹤更深點(diǎn)
它很容易使用以及可以做很多事,前提是大家都已經(jīng)安裝了htop!
現(xiàn)在,找你所想的進(jìn)程,僅僅需要按:
- s 顯示系統(tǒng)調(diào)用跟蹤(strace)
- L 顯示庫調(diào)用跟蹤(ltrace)
- l 顯示lsof
監(jiān)視
沒有更好的替代品了,服務(wù)器持續(xù)監(jiān)視,你曾經(jīng)是否發(fā)現(xiàn)自己使用奇奇怪怪的跟蹤方法去找出為什么哪里慢了以及資源怎么被消耗了,那么不要再被iotop, iftop, htop, iostat, vmstat等等煩擾了,趕快使用dstat吧,它可以做大多數(shù)上述的提到的工具能做的,而且可以做得更好!
它會(huì)以緊湊,時(shí)尚的代碼著色(親,不像iostat, vmstat喲)持續(xù)顯示你的數(shù)據(jù),而且你可以一直看到以往的數(shù)據(jù)(與iftop, iotop, htop不同喲)。
僅僅運(yùn)行這個(gè):
dstat --cpu --io --mem --net --load --fs --vm --disk-util --disk-tps --freespace --swap --top-io --top-bio-adv
還有一點(diǎn)就是這里還有更簡(jiǎn)單的方式來寫喲,如shell歷史記錄(shell history)或則重命名命令(aliases)
GDB
這是一個(gè)相當(dāng)復(fù)雜和強(qiáng)大的工具,但我僅僅涉及到基礎(chǔ)的東西(設(shè)置和基本命令)。
sudo apt-get install gdb python-dbg zcat /usr/share/doc/python2.7/gdbinit.gz > ~/.gdbinit run app with python2.7-dbg sudo gdb -p 12345
現(xiàn)在請(qǐng)使用:
bt- 堆棧軌跡(C 級(jí))
pystack- python 堆棧軌跡,前提是你需要擁有~/.gdbinit 并使用python-dbg
c(繼續(xù))
有出現(xiàn) segfaults 么 ?用 faulthandler !
除了Python 3.3其他的都會(huì)出現(xiàn)這個(gè)可怕的錯(cuò)誤, 回到Python 2.x
只要按照下面來做,你至少會(huì)找到一條導(dǎo)致段錯(cuò)誤的原因。
>>> import faulthandler >>> faulthandler.enable()
內(nèi)存泄露
好的,這里有許多工具,其中有一些是專門用于WSGI 應(yīng)用的,像Dozer,但是我最喜歡的無疑是 objgraph。它是如此驚人的方便和易于使用。它沒有與WSGI或任何其他東西繼承,所以你需要找到你自己的方式來運(yùn)行以下代碼:
>>> import objgraph >>> objs = objgraph.by_type("Request")[:15] >>> objgraph.show_backrefs(objs, max_depth=20, highlight=lambda v: v in objs, filename="/tmp/graph.png") Graph written to /tmp/objgraph-zbdM4z.dot (107 nodes) Image generated as /tmp/graph.png
你會(huì)得到一個(gè)像 這樣的圖表(警告:這個(gè)圖表非常大)。你也會(huì)得到 dot輸出。
內(nèi)存利用
有時(shí)你想使用更少的內(nèi)存。少分配內(nèi)存通常會(huì)使程序運(yùn)行的更快更好,用戶們都喜歡精益求精:)
有許多工具可以拿來使用 [1] ,但在我看來最好的是pytracemalloc - 與其他工具相比較,它的開銷很?。ú恍枰蕾囉谙魅跛俣鹊?sys.settrace)并且它的輸出非常詳盡。令人頭疼的是它的配置,因?yàn)樾枰阒鼐幾gpython,但是spt使其很容易做到。
只要運(yùn)行以下命令,然后你就可以去買午餐或者做其他事了:
apt-get source python2.7 cd python2.7-* wget https://github.com/wyplay/pytracemalloc/raw/master/python2.7_track_free_list.patch patch -p1 < python2.7_track_free_list.patch debuild -us -uc cd .. sudo dpkg -i python2.7-minimal_2.7*.deb python2.7-dev_*.deb
然后安裝pytracemalloc(請(qǐng)注意:如果你是在虛擬環(huán)境中做的這些操作,那么在python重新安裝后,你需要重建它-僅運(yùn)行virtualenv myenv即可):
pip install pytracemalloc
現(xiàn)在,你就可以通過以下代碼來封裝你的應(yīng)用程序:
import tracemalloc, time tracemalloc.enable() top = tracemalloc.DisplayTop( 5000, # log the top 5000 locations file=open('/tmp/memory-profile-%s' % time.time(), "w") ) top.show_lineno = True try: # code that needs to be traced finally: top.display()
會(huì)得到像下面這樣的輸出:
2013-05-31 18:05:07: Top 5000 allocations per file and line #1: .../site-packages/billiard/_connection.py:198: size=1288 KiB, count=70 (+0), average=18 KiB #2: .../site-packages/billiard/_connection.py:199: size=1288 KiB, count=70 (+0), average=18 KiB #3: .../python2.7/importlib/__init__.py:37: size=459 KiB, count=5958 (+0), average=78 B #4: .../site-packages/amqp/transport.py:232: size=217 KiB, count=6960 (+0), average=32 B #5: .../site-packages/amqp/transport.py:231: size=206 KiB, count=8798 (+0), average=24 B #6: .../site-packages/amqp/serialization.py:210: size=199 KiB, count=822 (+0), average=248 B #7: .../lib/python2.7/socket.py:224: size=179 KiB, count=5947 (+0), average=30 B #8: .../celery/utils/term.py:89: size=172 KiB, count=1953 (+0), average=90 B #9: .../site-packages/kombu/connection.py:281: size=153 KiB, count=2400 (+0), average=65 B #10: .../site-packages/amqp/serialization.py:462: size=147 KiB, count=4704 (+0), average=32 B ...
相關(guān)文章
python使用正則表達(dá)式匹配txt特定字符串(有換行)
這篇文章主要給大家介紹了關(guān)于python使用正則表達(dá)式匹配txt特定字符串的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12使用Python三角函數(shù)公式計(jì)算三角形的夾角案例
這篇文章主要介紹了使用Python三角函數(shù)公式計(jì)算三角形的夾角案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04將python圖片轉(zhuǎn)為二進(jìn)制文本的實(shí)例
今天小編就為大家分享一篇將python圖片轉(zhuǎn)為二進(jìn)制文本的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01Python巧用SnowNLP實(shí)現(xiàn)生成srt字幕文件
SnowNLP是一個(gè)可以方便的處理中文文本內(nèi)容的python類庫,本文主要為大家詳細(xì)介紹了Python如何巧用SnowNLP實(shí)現(xiàn)將一段話一鍵生成srt字幕文件,感興趣的可以了解下2024-01-01Python定義函數(shù)實(shí)現(xiàn)累計(jì)求和操作
這篇文章主要介紹了Python定義函數(shù)實(shí)現(xiàn)累計(jì)求和操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-05-05Python內(nèi)置庫之webbrowser模塊用法詳解
webbrowser模塊是Python自帶的標(biāo)準(zhǔn)庫,無需安裝,可以直接在Python中使用該模塊來打開網(wǎng)頁、PDF文件等,本文給大家詳細(xì)介紹了Python webbrowser模塊用法,需要的朋友可以參考下2023-08-08Python實(shí)現(xiàn)url長(zhǎng)短鏈接的轉(zhuǎn)換
短鏈接,通俗來說,就是將長(zhǎng)的URL網(wǎng)址,通過程序計(jì)算等方式,轉(zhuǎn)換為簡(jiǎn)短的網(wǎng)址字符串。本文將用Python語言實(shí)現(xiàn)這一效果,需要的可以參考一下2022-11-11