python錯誤調試print、assert、logging、pdb、pdb.set_trace()


世界人都知道,程序總會有bug存在。復雜點的bug一般人不能一眼看出,這就一要一套調試程序的手段。

方法一:使用print()函數直接打印:

>>> def foo(s):
...     n = int(s)
...     print(n)
...     return 10 / n
...
>>> def main():
...     foo('0')
...
>>> main()
0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in main
  File "<stdin>", line 4, in foo
ZeroDivisionError: division by zero

我們在認為可能出錯的地方打印變量出來。這有很大的弊端,因為打印的代碼實際功能並不需要。這都是垃圾信息。

方法二:用斷言assert代替打印print()

>>> def foo(s):
...     n = int(s)
...     assert n != 0,'n的值是0!'
...     return 10 / n
...
>>> def main():
...     foo('0')
...
>>> main()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in main
  File "<stdin>", line 3, in foo
AssertionError: n的值是0!

assert的意思是,緊跟其后的表達式的結果應該是true,否則會拋出AssertionError。這里 n = 0,所以結果是AssertionError: n的值是0!

如果assert僅僅這樣的話,那和print區別也不大嘛。下面就是assert特點嘍:啟動python解釋器的時候可以用-O參數來關閉assert(這是大寫的字母O;關閉后,可以把assert的語句當做pass用),將上述代碼放進新建文件err_assert.py中,執行結果:

PS E:\Python3.6.3\workspace> python -O err_assert.py
Traceback (most recent call last):
  File "err_assert.py", line 9, in <module>
    main()
  File "err_assert.py", line 7, in main
    foo('0')
  File "err_assert.py", line 4, in foo
    return 10 / n
ZeroDivisionError: division by zer

方法三:用logging替換print(),和assert比,logging不會拋出錯誤,而是可以輸出到文件中

新建一個err_logginginfo.py文件:

import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n=%d' % n)
print(10/n)

#執行結果
PS E:\Python3.6.3\workspace> python err_logginginfo.py INFO:root:n=0 Traceback (most recent call last): File "err_logginginfo.py", line 6, in <module> print(10/n) ZeroDivisionError: division by zero

logging可以允許你指定記錄信息的級別,級別由低到高分別有debug、info、warning、error、CRITICAL等級別,定義為高級別的時候,低級別的信息就不在顯示了。比如,我們調整為WARNING級別,看看INFO還有作用嗎:

import logging
logging.basicConfig(level=logging.WARNING)
s = '0'
n = int(s)
logging.info('n=%d' % n)
print(10/n)

執行結果:

PS E:\Python3.6.3\workspace> python err_logginginfo.py
Traceback (most recent call last):
  File "err_logginginfo.py", line 6, in <module>
    print(10/n)
ZeroDivisionError: division by zero

這樣,我們可以放心輸出不同級別的信息,也不用刪除。統一的控制輸出哪個級別的信息。

上述例子中,logging都是把結果輸出到控制台console,logging可實現的作用非常豐富,例如,我們簡單配置后,還可以把結果輸出到文件,甚至通過tcp協議,將日志內容發送到網絡。

方法四:使用python的調試器pdb,可以讓程序以單步方式執行,方便我們隨時查看運行狀態。

新建程序err_pdb.py文件:

s = '0'
n = int(s)
print(10 / n)

然后以pdb模式啟動:

PS E:\Python3.6.3\workspace> python -m pdb err_pdb.py
> e:\python3.6.3\workspace\err_pdb.py(1)<module>()
-> s = '0'
(Pdb) l
  1  -> s = '0'
  2     n = int(s)
  3     print(10 / n)
[EOF]
(Pdb) n
> e:\python3.6.3\workspace\err_pdb.py(2)<module>()
-> n = int(s)
(Pdb) p s
'0'
(Pdb) p n
*** NameError: name 'n' is not defined
(Pdb) n
> e:\python3.6.3\workspace\err_pdb.py(3)<module>()
-> print(10 / n)
(Pdb) p n
0
(Pdb) p s
'0'
(Pdb) n
ZeroDivisionError: division by zero
> e:\python3.6.3\workspace\err_pdb.py(3)<module>()
-> print(10 / n)
(Pdb) n
--Return--
> e:\python3.6.3\workspace\err_pdb.py(3)<module>()->None
-> print(10 / n)
(Pdb) n
ZeroDivisionError: division by zero
> <string>(1)<module>()->None
(Pdb) n
--Return--
> <string>(1)<module>()->None
(Pdb) n
Traceback (most recent call last):
  File "E:\Python3.6.3\lib\pdb.py", line 1667, in main
    pdb._runscript(mainpyfile)
  File "E:\Python3.6.3\lib\pdb.py", line 1548, in _runscript
    self.run(statement)
  File "E:\Python3.6.3\lib\bdb.py", line 431, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "e:\python3.6.3\workspace\err_pdb.py", line 3, in <module>
    print(10 / n)
ZeroDivisionError: division by zero
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> e:\python3.6.3\workspace\err_pdb.py(3)<module>()->None
-> print(10 / n)
(Pdb) q
Post mortem debugger finished. The err_pdb.py will be restarted
> e:\python3.6.3\workspace\err_pdb.py(1)<module>()
-> s = '0'
(Pdb) n
> e:\python3.6.3\workspace\err_pdb.py(2)<module>()
-> n = int(s)
(Pdb) q
PS E:\Python3.6.3\workspace>

小寫字母l,可以列出所有要執行的代碼;

n 命令表示單步執行代碼;

p 后面加上變量名,可以隨時查看變量的值;

在pdb模式中,對於還沒有單步執行到的代碼,相關的變量的變更是無效的;

q 命令退出當前調試,進入重新從頭開始調試,再次輸入q,就會推出調試程序。

這種方式的調試,有一個弊端,就是只能一步一步的執行下去,如果程序有很多行,豈不是累死。

方法五:在可能出錯的地方使用pdb.set_trace(),就可以設置一個斷電:

#err_pdb.py
import pdb

s = '0'
n = int(s)
pdb.set_trace() #程序運行到這里會自動停止,等待命令
print(10 / n)

這時,我們可以使用l、c、n、p、q等命令來控制和查看程序:

PS E:\Python3.6.3\workspace> python err_pdb.py
> e:\python3.6.3\workspace\err_pdb.py(7)<module>()
-> print(10 / n)
(Pdb) p s
'0'
(Pdb) l
  2     import pdb
  3
  4     s = '0'
  5     n = int(s)
  6     pdb.set_trace() #程序運行到這里會自動停止,等待命令
  7  -> print(10 / n)
[EOF]
(Pdb) n
ZeroDivisionError: division by zero
> e:\python3.6.3\workspace\err_pdb.py(7)<module>()
-> print(10 / n)
(Pdb) c
Traceback (most recent call last):
  File "err_pdb.py", line 7, in <module>
    print(10 / n)
ZeroDivisionError: division by zero

方法六:中級調試武器,IDE。省略若干網頁……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM