Python已經學了這麼久了,你如今已經長大了,該學會本身調試代碼了!相信你們在編寫程序過程當中會遇到大量的錯誤信息,我也不例外的啦~遇到這些問題該怎麼解決呢?使用最多的方法就是使用print打印中間變量了哇,關於這種方法怎麼說呢~low!!!這一節將記錄Python中一項很重要的技能:Debug(代碼調試),Here We Go!html
一個程序員在編寫項目的時候,敲代碼其實並不會佔用太多的時間,佔用時間的實際上是敲代碼以前(整個項目的思路和框架)和敲代碼以後(調試代碼)。調試代碼這個過程是最讓人煩心的事情了,真的是煩到脫髮~因而有一項過硬的Debug技巧將會減緩掉頭髮的速度。Debug的方法有不少,最經常使用的就是:打印中間變量(print)、使用日誌模塊(logging)、使用代碼調試模塊(pdb或ipdb)。接下來將會一一講解python
在程序報錯或者結果與預期不符合時,在源代碼中直接使用print函數打印中間變量進行檢查。程序員
1 ''' 2 從下列段落中提取出全部數字,並輸出 3 本例結果應該是:49737 4 ''' 5 import re 6 7 8 test = ''' JAKARTA, Indonesia—Flag carrier Garuda Indonesia said it is seeking to cancel an order for 49 Boeing Co. 737 MAX jets, saying passengers have lost confidence in the aircraft following two deadly crashes in recent months. ''' 9 10 pattern = re.compile('\d') 11 12 result = re.findall(pattern, test) 13 14 print(result[0] + result[1]) 15 16 # 運行結果: 17 49
題目要求輸出49737,可是本身的程序卻只輸出了49,這是怎麼回事呢?編程
那就使用print打印一下result這個變量的內容哇,因而,在第13行代碼中加入 print(result) :框架
1 ''' 2 從下列段落中提取出全部數字,並輸出 3 本例結果應該是:49737 4 ''' 5 import re 6 7 8 test = ''' JAKARTA, Indonesia—Flag carrier Garuda Indonesia said it is seeking to cancel an order for 49 Boeing Co. 737 MAX jets, saying passengers have lost confidence in the aircraft following two deadly crashes in recent months. ''' 9 10 pattern = re.compile('\d') 11 12 result = re.findall(pattern, test) 13 print(result) 14 15 print(result[0] + result[1])
# 運行結果: ['4', '9', '7', '3', '7'] 49
這時就會發現原來是result變量有誤,預期result效果爲['49', '737']ide
因而回過頭去檢查pattern,發現是pattern的鍋,應將pattern改成:函數
pattern = re.compile('\d+')
因而整個程序變爲:學習
3 ''' 4 從下列段落中提取出全部數字,並輸出 5 本例結果應該是:49737 6 ''' 7 import re 8 9 10 test = ''' JAKARTA, Indonesia—Flag carrier Garuda Indonesia said it is seeking to cancel an order for 49 Boeing Co. 737 MAX jets, saying passengers have lost confidence in the aircraft following two deadly crashes in recent months. ''' 11 12 # pattern = re.compile('\d') 13 pattern = re.compile('\d+') 14 15 result = re.findall(pattern, test) 16 print(result) 17 18 print(result[0] + result[1])
# 運行結果: ['49', '737'] 49737
結果與預期同樣,最後再將 print(result) 這一行刪除,整個程序就完工了。spa
『防抄襲:讀者請忽略這段文字,文章做者是博客園的MinuteSheep』命令行
優勢:
缺點:
日誌是個什麼鬼呢?感受好像日記的樣子哎~日誌其實和日記是有很大差異的,日誌是用來追蹤程序運行過程當中發生的事情,將這些事情按照必定的格式寫入特定的文件中,之後能夠經過分析日誌,讓管理者更加方便地瞭解整個程序的的運行狀況,尤爲是瞭解到程序的健康狀態(優秀的日誌分析者甚至能夠經過日誌分析出開發者的操做習慣和興趣愛好),最後根據這些結果爲程序打上合適的補丁。
在講Python日誌方法以前,先來了解一下日誌中最重要的等級制度:
一般日誌分爲5個等級:DEBUG, INFO, WARNING, ERROR, CRITICAL
平常編程過程當中應該見過WARNING和ERROR吧,一個是警告,一個是錯誤
從這些單詞的英文釋義就能夠知道每一個等級的權重了,DEBUG等級最小,CRITICAL等級最大
還有更詳細的等級分法:DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY
Python中用來記錄日誌的模塊爲:logging,這是一個內置標準庫
logging模塊的日誌等級有5個:DEBUG, INFO, WARNING, ERROR, CRITICAL,另外,logging模塊支持用戶自定義其餘等級,但這並不推薦,由於自定義的等級一般會形成等級混亂,極其容易和他人開發的程序衝突。
日誌等級 等級說明
DEBUG 詳細信息,一般僅在診斷問題時纔有意義
INFO 詳細程度僅次於DEBUG,確認事情按預期工做。
WARNING 表示發生了意外狀況,或代表在不久的未來出現了一些問題,但該軟件仍在按預期工做。
ERROR 因爲更嚴重的問題,該軟件沒法執行某些功能。
CRITICAL 嚴重錯誤,代表程序自己可能沒法繼續運行。
1 import logging 2 3 logging.debug('My level is debug') 4 logging.info('My level is info') 5 logging.warning('My level is warning') 6 logging.error('My level is error') 7 logging.critical('My level is critical')
上述代碼就是5種不一樣級別日誌的使用方法,運行一下看看結果如何:
# 運行結果 WARNING:root:My level is warning ERROR:root:My level is error CRITICAL:root:My level is critical
這時必定在疑惑,明明是五個等級啊,怎麼只輸出了後三個等級的內容
logging模塊雖然有5的等級,可是他的默認最小等級是WARNING,也就是說,logging模塊會自動忽略WARNING如下的等級,那怎麼才能輸出5個等級的內容呢?
須要在全部輸出語句以前配置日誌,看例:
1 import logging 2 3 logging.basicConfig(level=logging.DEBUG) # 配置日誌 4 5 logging.debug('My level is debug') 6 logging.info('My level is info') 7 logging.warning('My level is warning') 8 logging.error('My level is error') 9 logging.critical('My level is critical')
# 運行結果: DEBUG:root:My level is debug INFO:root:My level is info WARNING:root:My level is warning ERROR:root:My level is error CRITICAL:root:My level is critical
那麼問題來了, logging.basicConfig 是個什麼鬼呢?這個其實就是日誌的配置函數,能夠配置日誌等級、日誌輸出文件、日誌文件的打開模式(默認是追加)、日誌格式、日期格式等,這些選項對應的參數分別爲:level、filename 、filemode、format、datefmt,舉個例子:
1 import logging 2 3 logging.basicConfig(level=logging.DEBUG, filename='test.log') 4 5 logging.debug('My level is debug') 6 logging.warning('My level is warning') 7 logging.error('My level is error')
運行以後會發現屏幕並無日誌信息,而是在當前目錄下生成一個文件名爲‘test.log’的日誌文件,打開看一下這個文件:
DEBUG:root:My level is debug WARNING:root:My level is warning ERROR:root:My level is error
能夠看到已經將日誌寫入到指定文件了,這樣就能夠將日誌保存下來供之後分析利用了。
有的小夥伴會說,本身能不能修改日誌的輸出格式呢?好比想要加入時間,徹底沒有問題,這就要使用format參數了,關於format參數的使用,在下面羅列了一張表格供你們參考:
1 使用格式 概述 2 %(asctime)s 日誌發生時間 3 %(created)f 日誌發生時間戳 4 %(relativeCreated)d 日誌發生時間相對於logging模塊加載時間的相對毫秒 5 %(msecs)d 日誌發生時間的毫秒部分 6 %(levelname)s 日誌發生的文字等級(debug、info、warning、error、critical) 7 %(levelno)s 日誌發生的數字等級(十、20、30、40、50) 8 %(name)s 日誌記錄器名稱(默認是root) 9 %(message)s 日誌文本內容 10 %(pathname)s 調用日誌的源代碼的絕對路徑 11 %(filename)s pathname的文件名部分,包括後綴名 12 %(module)s filename的文件名部分,不包含後綴名 13 %(lineno)d 調用日誌的源代碼的行數 14 %(funcName)s 調用日誌的函數名 15 %(process)d 進程號 16 %(prscessName)s 進程名 17 %(thread)d 線程號 18 %(thread)s 線程名
舉個例子:
1 import logging 2 3 LOG_FORMAT = '%(asctime)s - %(levelname)s - %(name)s - %(message)s' 4 logging.basicConfig(level=logging.DEBUG, filename='test.log', format = LOG_FORMAT) 5 6 logging.debug('My level is debug') 7 logging.warning('My level is warning') 8 logging.error('My level is error')
查看‘test.log’:
DEBUG:root:My level is debug WARNING:root:My level is warning ERROR:root:My level is error 2019-03-24 10:52:46,093 - DEBUG - root - My level is debug 2019-03-24 10:52:46,094 - WARNING - root - My level is warning 2019-03-24 10:52:46,094 - ERROR - root - My level is error
能夠看到日誌輸出格式明顯發生了改變
注意:打開文件模式默認爲追加
若是想要改變時間的輸出格式,須要使用datefmt參數,要注意datefmt參數要在format參數裏有時間的前提下才會生效,這裏就不在舉例了,關於時間的格式能夠參考time模塊時的講解
之後再介紹哇,基本的使用方法已經能夠知足使用了,高級使用方法比較複雜,之後再更新
pdb是Python內置的Debug模塊,可是其功能不夠強大,因而便有了第三方模塊ipdb的出現;它們兩個的關係就好像python和ipython的關係。
ipdb調試代碼是比print函數更加高級和靈活的方式,應當熟練應用ipdb的使用方式,而且取代print這種low方法🐔🚄
ipdb不須要入侵源代碼,能夠按步執行,能夠打斷點,能夠在程序運行時查看變量值,能夠在程序運行時修改變量值,盤它!
pip install ipdb
『防抄襲:讀者請忽略這段文字,文章做者是博客園的MinuteSheep』
學習ipdb,心中要有一張表:
命令 說明
next或n 執行下一行
exit或q 終止程序並退出
p或pp 打印變量
! 修改變量
list或l 查看當前程序代碼
break或b 設置斷點
continue或c 繼續執行程序直到遇到斷點
step或s 進入函數
return或r 在函數中使用,執行代碼直到遇到斷點或者函數結束
help 幫助
使用ipdb時,能夠在代碼內部提早導入ipdb模塊,但這一般是不現實的;一般採起的方法是這樣的,在命令行輸入:
python -m ipdb xxx.py
輸入以上命令後,便會進入ipdb的debug交互模式,接下來開始舉例(多圖警告):
案例代碼:
1 # This is a test for ipdb 2 # Author: MinuteSheep<minutesheep@163.com> 3 4 import time 5 import math 6 7 8 def get_p_time(): 9 present_time = time.asctime() 10 return present_time 11 12 13 a = 123 14 b = 456 15 16 c = a + b 17 18 print(c) 19 20 present_time = get_p_time() 21 22 print(present_time)
案例1: 使用n
在命令輸入 python -m ipdb 4.py 後,會出現以下交互模式:
聰明的你已經發現代碼一進入就執行到了第4行,其實這也很好理解,前面3行都是註釋嘛,對代碼的執行並無實際做用,ipdb遇到註釋語句會自動跳過的
接下來輸入一個n,讓那個代碼繼續執行一行:
能夠看到返回的結果在動態的運行,多輸入幾回看看效果哇:
執行屢次n後,程序按照預計的順序執行
注意:執行到18行遇到print(c),可是並無當即返回結果,那是由於箭頭位置是指將要執行這一行了,本次並不會執行,全部下一步才輸出c的值579
注意:程序執行到第8行代碼時,遇到定義函數,這時在執行下一行時,代碼會跳過函數部分,直接來到13行
案例2: 使用exit或q
輸入exit或q便會直接退出🙈
案例3: p或pp
上面圖片中能夠看到使用p或pp打印變量的值
『防抄襲:讀者請忽略這段文字,文章做者是博客園的MinuteSheep』
案例4: 使用!
由上圖可知:想要修改變量須要在變量前面加一個!
案例5: 使用list或l
當你調試代碼過程當中忘記了程序執行到哪裏了的時候,可使用l來查看一下,效果如上圖
案例6: 使用step或s
當遇到執行函數時,默認會在後臺執行完函數而且指向下一行代碼,可是按照咱們的思惟,當遇到執行函數時,須要返回頭去看看函數時怎麼運行的,想要看看代碼在函數中時如何一步一步運行的,使用s便可:
ipdb基本使用方法就這些,還有一點關於斷點的使用,下次補充更新🙉