1.錯誤處理

try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError: ##最后一個except子句可以忽略例外的名稱,它將被當作通配符使用
print('ZeroDivisionError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
finally一定會被執行(可以沒有finally陳述句),
如果一個例外沒有與任何的 excep 匹配,那么這個例外將會傳遞給上層的 try 中,
一個except子句可以同時處理多個例外,這些例外將被放在一個括號里成為一個元組,例如: except (RuntimeError, TypeError, NameError): pass
如果沒有錯誤發生,可以在except陳述句塊后面加一個else,當沒有錯誤發生時,會自動執行else陳述句
Python所有的錯誤都是從BaseException類派生的,寫錯誤類的時候,可能會其子類也“一網打盡”,注意范圍,
常見的錯誤型別和繼承關系看這里:https://docs.python.org/3/library/exceptions.html#exception-hierarchy
捕獲錯誤,可以多層呼叫,
出錯的時候,一定要分析錯誤的呼叫堆疊資訊,才能定位錯誤的位置,
Python內置的logging模塊可以非常容易地記錄錯誤資訊:
# err_logging.py import logging def foo(s): return 10 / int(s) def bar(s): return foo(s) * 2 def main(): try: bar('0') except Exception as e: logging.exception(e) main() print('END')
同樣是出錯,但程式列印完錯誤資訊后會繼續執行,并正常退出,
raise 陳述句有如下三種常用的用法:
- raise:單獨一個 raise,該陳述句引發當前背景關系中捕獲的例外(比如在 except 塊中),或默認引發 RuntimeError 例外,
- raise 例外類名稱:raise 后帶一個例外類名稱,表示引發執行型別的例外,
- raise 例外類名稱(描述資訊):在引發指定型別的例外的同時,附帶例外的描述資訊,
如果要拋出錯誤,首先根據需要,可以定義一個錯誤的class,選擇好繼承關系,然后,用raise陳述句拋出一個錯誤的實體:
# err_raise.py class FooError(ValueError): pass def foo(s): n = int(s) if n==0: raise FooError('invalid value: %s' % s) return 10 / n foo('0')
只有在必要的時候才定義我們自己的錯誤型別,如果可以選擇Python已有的內置的錯誤型別(比如ValueError,TypeError),盡量使用Python內置的錯誤型別,
# err_reraise.py def foo(s): n = int(s) if n==0: raise ValueError('invalid value: %s' % s) return 10 / n def bar(): try: foo('0') except ValueError as e: print('ValueError!') raise bar()
raise陳述句如果不帶引數,就會把當前錯誤原樣拋出,
raise 唯一的一個引數指定了要被拋出的例外,它必須是一個例外的實體或者是例外的類(也就是 Exception 的子類),
在except中raise一個Error,還可以把一種型別的錯誤轉化成另一種型別:只要是合理的轉換邏輯就可以
try: 10 / 0 except ZeroDivisionError: raise ValueError('input error!')
try:
a = input("輸入一個數:")
#判斷用戶輸入的是否為數字
if(not a.isdigit()):
raise ValueError("a 必須是數字")
except ValueError as e:
print("引發例外:",repr(e))
print("end")
result:
輸入一個數:a
引發例外: ValueError('a 必須是數字')
end
當用戶輸入的不是數字時,程式會進入 if 判斷陳述句,并執行 raise 引發 ValueError 例外,但由于其位于 try 塊中,因為 raise 拋出的例外會被 try 捕獲,并由 except 塊進行處理,
因此,雖然程式中使用了 raise 陳述句引發例外,但程式的執行是正常的,手動拋出的例外并不會導致程式崩潰,
除了這個,上面的raise 例子中,執行到raise,就退出了,
2.除錯
1.用print()把可能有問題的變數列印出來看看,
2.凡是用print()來輔助查看的地方,都可以用斷言(assert)來替代,
def foo(s): n = int(s) assert n != 0, 'n is zero!' return 10 / n def main(): foo('0')
assert的意思是,運算式n != 0應該是True,否則,根據程式運行的邏輯,后面的代碼肯定會出錯,
如果斷言失敗,assert陳述句本身就會拋出AssertionError:
$ python err.py Traceback (most recent call last): ... AssertionError: n is zero!
啟動Python解釋器時可以用-O引數來關閉assert,關閉后,你可以把所有的assert陳述句當成pass來看,
3.logging不會拋出錯誤,而且可以輸出到檔案,logging.info()就可以輸出一段文本
import logging logging.basicConfig(level=logging.INFO) s = '0' n = int(s) logging.info('n = %d' % n) print(10 / n)
它允許你指定記錄資訊的級別,有debug,info,warning,error等幾個級別,當我們指定level=INFO時,logging.debug就不起作用了,
logging的另一個好處是通過簡單的配置,一條陳述句可以同時輸出到不同的地方,比如console和檔案,
4.啟動Python的除錯器pdb,
import pdb,然后,在可能出錯的地方放一個pdb.set_trace(),就可以設定一個斷點:
# err.py import pdb s = '0' n = int(s) pdb.set_trace() # 運行到這里會自動暫停 print(10 / n)
運行代碼,程式會自動在pdb.set_trace()暫停并進入pdb除錯環境,可以用命令p查看變數,或者用命令c繼續運行
Pycharm的除錯程式:https://blog.csdn.net/s740556472/article/details/90054266
3.單元測驗
單元測驗是用來對一個模塊、一個函式或者一個類來進行正確性檢驗的測驗作業,
需要引入Python自帶的unittest模塊.
用到再細查,大體是看懂了,一定要做單元測驗,減少測驗人員的作業量,也減少很多不必要的錯誤,
單元測驗的測驗用例要覆寫常用的輸入組合、邊界條件和例外,
# -*- coding: utf-8 -*- import unittest class Student(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): # if self.score < 0 or self.score > 100: # raise ValueError('ValueError') if self.score >= 60 and self.score < 80: return 'B' elif self.score >= 80 and self.score <= 100: return 'A' elif self.score >= 0 and self.score < 60: return 'C' else: raise ValueError("wrong key") class TestStudent(unittest.TestCase): def test_80_to_100(self): s1 = Student('Bart', 80) s2 = Student('Lisa', 100) self.assertEqual(s1.get_grade(), 'A') self.assertEqual(s2.get_grade(), 'A') def test_60_to_80(self): s1 = Student('Bart', 60) s2 = Student('Lisa', 79) self.assertEqual(s1.get_grade(), 'B') self.assertEqual(s2.get_grade(), 'B') def test_0_to_60(self): s1 = Student('Bart', 0) s2 = Student('Lisa', 59) self.assertEqual(s1.get_grade(), 'C') self.assertEqual(s2.get_grade(), 'C') def test_invalid(self): s1 = Student('Bart', -1) s2 = Student('Lisa', 101) with self.assertRaises(ValueError): s1.get_grade() with self.assertRaises(ValueError): s2.get_grade() if __name__ == '__main__': unittest.main()
4.檔案測驗
# -*- coding: utf-8 -*- def fact(n): ''' Calculate 1*2*...*n >>> fact(1) 1 >>> fact(10) 3628800 >>> fact(-1) Traceback (most recent call last): File "C:\python\lib\doctest.py", line 1329, in __run compileflags, 1), test.globs) File "<doctest __main__.fact[2]>", line 1, in <module> fact(-1) File "C:/Workspace/Document/Private/Code/python/tutorial/study.py", line 917, in fact raise ValueError() ValueError ''' if n < 1: raise ValueError() if n == 1: return 1 return n * fact(n - 1) if __name__ == '__main__': import doctest doctest.testmod()
Python內置的“檔案測驗”(doctest)模塊可以直接提取注釋中的代碼并執行測驗,
doctest嚴格按照Python互動式命令列的輸入和輸出來判斷測驗結果是否正確,只有測驗例外的時候,可以用...表示中間一大段煩人的輸出,
當模塊正常匯入時,doctest不會被執行,只有在命令列直接運行時,才執行doctest,所以,不必擔心doctest會在非測驗環境下執行,
5. warnings
warnings.warn(message, category=None, stacklevel=1, source=None)
發出警告,或者忽略它或引發例外, 有時間或遇見再細看吧,
參考自:廖老師的python3和菜鳥
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/161512.html
標籤:Python
上一篇:Python3標準庫:urllib.parse分解URL
下一篇:Python基礎
