#7 Python代碼調試

来源:https://www.cnblogs.com/minutesheep/archive/2019/03/31/10579092.html
-Advertisement-
Play Games

本篇博文主要記錄Python的Debug方法:print()、logging、ipdb ...


前言

Python已經學了這麼久了,你現在已經長大了,該學會自己調試代碼了!相信大家在編寫程式過程中會遇到大量的錯誤信息,我也不例外的啦~遇到這些問題該怎麼解決呢?使用最多的方法就是使用print列印中間變數了哇,關於這種方法怎麼說呢~low!!!這一節將記錄Python中一項很重要的技能:Debug(代碼調試),Here We Go!

一、代碼調試概述

1.1 概述

一個程式員在編寫項目的時候,敲代碼其實並不會占用太多的時間,占用時間的其實是敲代碼之前(整個項目的思路和框架)和敲代碼之後(調試代碼)。調試代碼這個過程是最讓人煩心的事情了,真的是煩到脫髮~於是有一項過硬的Debug技巧將會減緩掉頭髮的速度。Debug的方法有很多,最常用的就是:列印中間變數(print)、使用日誌模塊(logging)、使用代碼調試模塊(pdb或ipdb)。接下來將會一一講解

二、Debug方法一:print函數

2.1 print方法適用情景

在程式報錯或者結果與預期不符合時,在源代碼中直接使用print函數列印中間變數進行檢查。

2.2 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']

於是回過頭去檢查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) 這一行刪除,整個程式就完工了。

『防抄襲:讀者請忽略這段文字,文章作者是博客園的MinuteSheep

2.3 print方法優缺點

優點:

  • 理解和操作方便簡單,上手難度低
  • 在編寫程式中可以一步一步檢查中間變數是否符合預期

缺點:

  • 直接入侵源代碼,如果操作失誤可能會造成不可輓救的後果
  • 調試完成後需要將這些print行刪除掉或者註釋掉,否則會造成整個程式運行結果複雜,同時太多print函數的出現會嚴重拖慢運行速度

三、Debug方法二:logging模塊

3.1 日誌概述

日誌是個什麼鬼呢?感覺好像日記的樣子哎~日誌其實和日記是有很大差別的,日誌是用來追蹤程式運行過程中發生的事情,將這些事情按照一定的格式寫入特定的文件中,以後可以通過分析日誌,讓管理者更加方便地瞭解整個程式的的運行情況,尤其是瞭解到程式的健康狀態(優秀的日誌分析者甚至可以通過日誌分析出開發者的操作習慣和興趣愛好),最後根據這些結果為程式打上合適的補丁。

3.2 日誌作用

  • 代碼調試
  • 記錄程式的運行狀況
  • 為程式打補丁提供支撐

3.3 日誌等級

在講Python日誌方法之前,先來瞭解一下日誌中最重要的等級制度:

通常日誌分為5個等級:DEBUG, INFO, WARNING, ERROR, CRITICAL

日常編程過程中應該見過WARNING和ERROR吧,一個是警告,一個是錯誤

從這些單詞的英文釋義就可以知道每個等級的權重了,DEBUG等級最小,CRITICAL等級最大

還有更詳細的等級分法:DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY

3.4 logging模塊簡介

Python中用來記錄日誌的模塊為:logging,這是一個內置標準庫

logging模塊的日誌等級有5個:DEBUG, INFO, WARNING, ERROR, CRITICAL,另外,logging模塊支持用戶自定義其他等級,但這並不推薦,因為自定義的等級通常會造成等級混亂,極其容易和他人開發的程式衝突。

日誌等級                                等級說明
DEBUG                       詳細信息,通常僅在診斷問題時才有意義
INFO                        詳細程度僅次於DEBUG,確認事情按預期工作。
WARNING                     表示發生了意外情況,或表明在不久的將來出現了一些問題,但該軟體仍在按預期工作。
ERROR                       由於更嚴重的問題,該軟體無法執行某些功能。
CRITICAL                    嚴重錯誤,表明程式本身可能無法繼續運行。

3.5 logging模塊使用方法

3.5.1 日誌基本使用方法

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                    日誌發生的數字等級(10、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模塊時的講解

3.5.2 日誌高級使用方法

以後再介紹哇,基本的使用方法已經可以滿足使用了,高級使用方法比較複雜,以後再更新

四、Debug方法三:pdb模塊和ipdb模塊

4.1 pdb和ipdb概述

pdb是Python內置的Debug模塊,但是其功能不夠強大,於是便有了第三方模塊ipdb的出現;它們兩個的關係就好像python和ipython的關係。

ipdb調試代碼是比print函數更加高級和靈活的方式,應當熟練應用ipdb的使用方式,並且取代print這種low方法

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • OCR,全稱Optical character recognition,或者optical character reader,中文譯名叫做光學文字識別。它是把圖像文件中的手寫文本,列印文本轉換為機器編碼文本的一種方法。 ...
  • 標題黨其實也不多,一個輸入層,三個隱藏層,一個輸出層 老樣子先上代碼 導入mnist的路徑很長,現在還記不住 設置輸入層,X為樣本數據,y是標簽值 X 784是因為28*28,None是因為不知道需要用多少樣本 Y 10是因為 0~9的預測輸出,None理由同上 3層這樣寫有點啰嗦 下一版有個用函數 ...
  • 一、單例模式 在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的一個類只有一個實例。即一個類只有一個對象實例。 二、分類 分為懶漢式和餓漢式兩種; 三、應用場景 1.需要頻繁實例化然後銷毀的對象。 2.創建對象時耗時過多或者耗資源過多,但又經常用到的對象。 3.有 ...
  • python assert 句語格式及用法很簡單。通常程式在運行完之後拋出異常,使用assert可以在出現有異常的代碼處直接終止運行。 而不用等到程式執行完畢之後拋出異常。 python assert的作用 python assert如果發生異常就說明表達示為假。可以理解表示式返回 值為假 時就會觸 ...
  • 在上一篇博客 "《程式員如何從0到1搭建自己的技術博客》" 中,我們瞭解瞭如何快速的從0到1搭建一個個人博客。 其實細心的你會發現,該博客用到了一個評論插件,這個插件就是Gitalk。 如果想要在博客中正確的使用該插件,還是需要修改下_config.yml里關於Gitalk的配置的。 也許你會好奇G ...
  • # ******************************練習****************************# 在控制臺中獲取兩個整數,作為迴圈開始和結束的點'''a = int(input('請輸入起點:'))b = int(input('請輸入終點:'))while a <= b ...
  • 1. zuul進階學習(二) 1.1. zuul對接apollo 1.1.1. Netflix Archaius 1.1.2. 定期拉 1.2. zuul生產管理實踐 1.2.1. zuul網關參考部署 1.2.2. 分集群過濾管理 1.2.3. 網關生產級部署實踐 1.2.4. Hystrix實時 ...
  • 本文用第三方類庫:yagmail 實現;以QQ郵箱作為發送郵箱為例。最終的實現效果:給指定郵箱,發送指定內容的郵件。 準備工作 1、用於發送郵件的賬號信息 比如賬號用自己的qq郵箱,但'密碼'需要在郵箱:設置--賬戶--開啟POP3/SMTP服務,開啟後會獲得授權碼(把它理解為'密碼'就行~)。 2 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...