python編程快速上手之第10章實踐項目參考答案,python快速上手
本章主要講了python程式的調試,當程式有BUG或異常的時候,我們如何調試代碼找出問題點。其實在本章之前的章節我們做練習的時候都會遇到各種各樣的錯語和異常,最初當不知道程式哪裡出錯的情況下不可否認的都使用了print語句進行輸出並調試代碼。沒錯print也是調試代碼的一種工具,直觀簡單,便也有缺點,就是調試好後要進行刪除,也是件麻煩事,於是就有了本章介紹的assert(斷言),logging(日誌)以及各種調試工具的出現。
首先來回顧一下python的異常。
一.python常見的異常類型
| 異常名稱 |
描述 |
| BaseException |
所有異常的基類 |
| SystemExit |
解譯器請求退出 |
| KeyboardInterrupt |
使用者中斷執行(通常是輸入^C) |
| Exception |
常規錯誤的基類 |
| StopIteration |
迭代器沒有更多的值 |
| GeneratorExit |
產生器(generator)發生異常來通知退出 |
| StandardError |
所有的內建標準異常的基類 |
| ArithmeticError |
所有數值計算錯誤的基類 |
| FloatingPointError |
浮點計算錯誤 |
| OverflowError |
數值運算超出最大限制 |
| ZeroDivisionError |
除(或模數)零 (所有資料類型) |
| AssertionError |
Assert 陳述式失敗 |
| AttributeError |
對象沒有這個屬性 |
| EOFError |
沒有內建輸入,到達EOF 標記 |
| EnvironmentError |
作業系統錯誤的基類 |
| IOError |
輸入/輸出操作失敗 |
| OSError |
作業系統錯誤 |
| WindowsError |
系統調用失敗 |
| ImportError |
匯入模組/對象失敗 |
| LookupError |
無效資料查詢的基類 |
| IndexError |
序列中沒有此索引(index) |
| KeyError |
映射中沒有這個鍵 |
| MemoryError |
記憶體溢出錯誤(對於Python 解譯器不是致命的) |
| NameError |
未聲明/初始化對象 (沒有屬性) |
| UnboundLocalError |
訪問未初始化的本地變數 |
| ReferenceError |
弱引用(Weak reference)試圖訪問已經記憶體回收了的對象 |
| RuntimeError |
一般的執行階段錯誤 |
| NotImplementedError |
尚未實現的方法 |
| SyntaxError |
Python 語法錯誤 |
| IndentationError |
縮排錯誤 |
| TabError |
Tab 和空格混用 |
| SystemError |
一般的解譯器系統錯誤 |
| TypeError |
對類型無效的操作 |
| ValueError |
傳入無效的參數 |
| UnicodeError |
Unicode 相關的錯誤 |
| UnicodeDecodeError |
Unicode 解碼時的錯誤 |
| UnicodeEncodeError |
Unicode 編碼時錯誤 |
| UnicodeTranslateError |
Unicode 轉換時錯誤 |
| Warning |
警告的基類 |
| DeprecationWarning |
關於被棄用的特徵的警告 |
| FutureWarning |
關於構造將來語義會有改變的警告 |
| OverflowWarning |
舊的關於自動提升為長整型(long)的警告 |
| PendingDeprecationWarning |
關於特性將會被廢棄的警告 |
| RuntimeWarning |
可疑的運行時行為(runtime behavior)的警告 |
| SyntaxWarning |
可疑的文法的警告 |
| UserWarning |
使用者代碼產生的警告 |
二.python異常處理
python處理異常的完整語句如下:實際程式中並不是每個語句都要用上,可以組合起來用。
try:
try_suite
except Exception1,Exception2,...,Argument:
exception_suite
...... #other exception block
else:
no_exceptions_detected_suite
finally:
always_execute_suite
具體用法請參見:
python2:http://www.runoob.com/python/python-exceptions.html
python3:http://www.runoob.com/python3/python3-errors-execptions.html
三.拋出異常
拋出異常使用raise語句。
文法:raise Exception(‘出錯資訊的字串’)
此語句直接在互動模式下運行則會直接報錯並返回Exception函數中的字串。一般情況下raise語句用在函數中,try和except語句在調用該函數的代碼中,在except語句中接收exception函數作為參數。
except Exception as err:
print(‘An exception happened:’ + str(err)
四.traceback模組使用traceback模組可以跟蹤異常並得到更祥細的出錯資訊,其實程式如果沒有進行異常處理但是確實有異常存在的時候,從螢幕輸出的資訊來看,我們都會看很祥細的出錯資訊,包括哪一行出錯,是什麼錯誤等等,這應該就是traceback模組返回的資訊,只是python本身幫我們拋出了異常。
在互動模式下,先匯入traceback模組,通過help()就可以查看traceback的協助資訊。
import traceback
help(traceback)
2個常用函數
format_exc()返回字串,print_exc()則直接給列印出來
五.斷言assert
使用assert語句檢查,如果失敗就拋出異常
文法:
assert 條件,’異常資訊’
例如:
In [16]: p = 1
In [17]: assert p==0,'error'
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-17-11c0bd0cc9d4> in <module>()
----> 1 assert p==0,'error'
AssertionError: error
六.logging日誌模組
Python的logging模組提供了通用的日誌系統,可以方便第三方模組或者是應用使用。這個模組提供不同的記錄層級,並可以採用不同的方式記錄日誌,共有5個層級
| 層級 |
日誌函數 |
描述 |
| DEBUG |
logging.debug() |
最低層級,用於小細節。通常只有在診斷問題時,你才會關心這些資訊 |
| INFO |
logging.info() |
用於記錄程式中一般的事件資訊,或確認一切工作正常 |
| WARNING |
logging.warning() |
用於表示可能的問題,它不阻止程式的工作,但將來可能會 |
| ERROR |
logging.error() |
用於記錄錯誤,它導致程式做某事失敗 |
| CRITICAL |
logging.critical() |
最進階別。用於表示致命的錯誤,它導致或將要導致程式完全停止 |
使用文法:
In [18]: import logging
In [19]: logging.basicConfig(level=logging.debug,format='%(asctime)s - %(levelname)s - %(message)s')
In [20]: logging.debug('some debugging details')
2017-04-28 23:36:39,795 - DEBUG - some debugging details
format,定義了最終log資訊的順序,結構和內容。
%(name)s Logger的名字
%(levelname)s 文本形式的記錄層級
%(message)s 使用者輸出的訊息
%(asctime)s 字串形式的目前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(levelno)s 數字形式的記錄層級
%(pathname)s 調用日誌輸出函數的模組的完整路徑名,可能沒有
%(filename)s 調用日誌輸出函數的模組的檔案名稱
%(module)s 調用日誌輸出函數的模組名
%(funcName)s 調用日誌輸出函數的函數名
%(lineno)d 調用日誌輸出函數的語句所在的程式碼
%(created)f 目前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌資訊時的,自Logger建立以 來的毫秒數
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
禁用日誌
In [21]: logging.disable(logging.debug)
將日誌寫入檔案
In [22]: logging.basicConfig(filename='mylog.txt',level=logging.debug,format='%(asctime)s - %(levelname)s - %(message)s')
7.實踐項目參考答案
#!/usr/bin/env python3.4
# debug.py
# create by mfyang 2017-04-28
import random
import logging
logging.basicConfig(level=logging.DEBUG,format=' %(asctime)s - %(levelname)s -%(message)s')
#logging.disable(logging.DEBUG)
logging.debug('start of program')
guess = ''
while guess not in ('heads','tails'):
print('Guess the coin toss! Enter heads or tails:')
guess = input()
logging.debug('you input is:' + str(guess))
toss = random.randint(0,1)
coinresult = ''
if toss == 0:
coinresult = 'tails'
if toss == 1:
coinresult = 'heads'
logging.debug('toss is(0 is tails 1 is heads):' + coinresult)
if coinresult == guess:
print('you got it!')
else:
print('Nope! Guess again')
guess = input()
logging.debug('you input is:' + str(guess))
if coinresult == guess:
print('You got it!')
else:
print('Nope. You are really bad at this game.')
logging.debug('end of debug')