1 python錯誤處理
1 try的運行機制
利用打印錯誤這種方式很low
def bar():
r = foo()
if r==(-1):
print('Error')
else:
pass
所以高級語言通常都內置了一套try…except…finally…的錯誤處理機制,Python也不例外。
try:
print('try...')
r = 10 / 0
print('result:', r)#這裏try後出現錯誤,則後續代碼不會繼續執行
except ZeroDivisionError as e:#如果有這個錯誤則跳到這裏進行處理,而不是處理後續代碼
print('except:', e)
finally:#如果有finally語句塊,則except後會執行
print('finally...')
print('END')
try...
('except:', ZeroDivisionError('integer division or modulo by zero',))
finally...
END
總結如下,try如果遇到錯誤不往下執行代碼,而是跳到except執行,然後再inally,再到最後跳過了錯誤?
沒有錯誤發生,所以except語句塊不會被執行,但是finally如果有,則一定會被執行(可以沒有finally語句)。
你還可以猜測,錯誤應該有很多種類,如果發生了不同類型的錯誤,應該由不同的except語句塊處理。沒錯,可以有多個except來捕獲不同類型的錯誤:
2 多類異常
try:
print('try...')
r = 10 / int('a')#int也可以拋出一個異常,判斷這個數是否爲整數
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
finally:
print('finally...')
print('END')
try...
('ValueError:', ValueError("invalid literal for int() with base 10: 'a'",))
finally...
END
#多類異常注意事項
try:
print str(1)
except ValueError as e:
print('ValueError')
except UnicodeError as e:
print('UnicodeError')
1
第二個except永遠也捕獲不到UnicodeError,因爲UnicodeError是ValueError的子類,如果有,也被第一個except給捕獲了。
常見異常類型及繼承關係如下:https://docs.python.org/3/library/exceptions.html#exception-hierarchy
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
File "<ipython-input-7-e0cfe9de490f>", line 2
+-- SystemExit
^
IndentationError: unexpected indent
3 錯誤的傳遞
# err.py:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
main()
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-10-1d7596361dc9> in <module>()
9 bar('0')
10
---> 11 main()
<ipython-input-10-1d7596361dc9> in main()
7
8 def main():
----> 9 bar('0')
10
11 main()
<ipython-input-10-1d7596361dc9> in bar(s)
4
5 def bar(s):
----> 6 return foo(s) * 2
7
8 def main():
<ipython-input-10-1d7596361dc9> in foo(s)
1 # err.py:
2 def foo(s):
----> 3 return 10 / int(s)
4
5 def bar(s):
ZeroDivisionError: integer division or modulo by zero
4 記錄錯誤
如果不捕獲錯誤,自然可以讓Python解釋器來打印出錯誤堆棧,但程序也被結束了。既然我們能捕獲錯誤,就可以把錯誤堆棧打印出來,然後分析錯誤原因,同時,讓程序繼續執行下去。
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')#拋出異常後繼續執行此句
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
File "<ipython-input-12-143dc3a3d615>", line 13, in main
bar('0')
File "<ipython-input-12-143dc3a3d615>", line 9, in bar
return foo(s) * 2
File "<ipython-input-12-143dc3a3d615>", line 6, in foo
return 10 / int(s)
ZeroDivisionError: integer division or modulo by zero
END
上面同樣是錯誤,但拋出異常然後再繼續執行了
5 拋出錯誤
利用raise可以拋出自己設置的錯誤
class FooError(ValueError):#新建一個異常類(選擇好繼承關係就好),可以用於拋出,因爲異常也是一個類
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n
foo('0')
---------------------------------------------------------------------------
FooError Traceback (most recent call last)
<ipython-input-15-8887d546fc87> in <module>()
8 return 10 / n
9
---> 10 foo('0')
<ipython-input-15-8887d546fc87> in foo(s)
5 n = int(s)
6 if n==0:
----> 7 raise FooError('invalid value: %s' % s)
8 return 10 / n
9
FooError: invalid value: 0
避免重複拋出異常
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()
ValueError!
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-16-ae878a7f35c1> in <module>()
12 raise
13
---> 14 bar()
<ipython-input-16-ae878a7f35c1> in bar()
7 def bar():
8 try:
----> 9 foo('0')
10 except ValueError as e:
11 print('ValueError!')
<ipython-input-16-ae878a7f35c1> in foo(s)
2 n = int(s)
3 if n==0:
----> 4 raise ValueError('invalid value: %s' % s)
5 return 10 / n
6
ValueError: invalid value: 0
# err_reraise.py
def foo(s):
# n = int(s)
# if n==0:
# raise ValueError('invalid value: %s' % s)
return 10 / s
def bar():
try:
foo(0)
except ValueError as e:
print('ValueError!')
raise
bar()
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-21-b83fbf519e8b> in <module>()
14 raise
15
---> 16 bar()
<ipython-input-21-b83fbf519e8b> in bar()
9 def bar():
10 try:
---> 11 foo(0)
12 except ValueError as e:
13 print('ValueError!')
<ipython-input-21-b83fbf519e8b> in foo(s)
5 # if n==0:
6 # raise ValueError('invalid value: %s' % s)
----> 7 return 10 / s
8
9 def bar():
ZeroDivisionError: integer division or modulo by zero
2 調試
1 斷言assert
def foo(n):
print type(n)
assert n != 0,'n is zero!'
return 10 / n
def main():
foo(0)
main()
<type 'int'>
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-26-4740780af009> in <module>()
5 def main():
6 foo(0)
----> 7 main()
<ipython-input-26-4740780af009> in main()
4 return 10 / n
5 def main():
----> 6 foo(0)
7 main()
<ipython-input-26-4740780af009> in foo(n)
1 def foo(n):
2 print type(n)
----> 3 assert n != 0,'n is zero!'
4 return 10 / n
5 def main():
AssertionError: n is zero!
2 logging
import logging
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-27-34acd0c1650a> in <module>()
4 n = int(s)
5 logging.info('n = %d' % n)
----> 6 print(10 / n)
ZeroDivisionError: integer division or modulo by zero
import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-28-7501ca4b96cb> in <module>()
4 n = int(s)
5 logging.info('n = %d' % n)
----> 6 print(10 / n)
ZeroDivisionError: integer division or modulo by zero
沒發現有啥用
3 pdb
python -m pdb err.py運行程序,可以用於調試代碼
l #查看代碼
n #下一步
p #打印
q #退出
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-29-27f5dfd249af> in <module>()
----> 1 l #查看代碼
2 n #下一步
3 p #打印
4 q #退出
NameError: name 'l' is not defined
pdb.set_trace()可以在想要的地方設置斷點
3單元測試
就是利用python自帶的unittest模塊,編寫一個測試類,裏面有很多種測試方法,批量的對代碼進行測試,這樣很方便,待代碼修改後還可以繼續調用,很好~~
class Dict(dict):
def __init__(self, **kw):
super().__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
import unittest
#from mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a=1, b='test')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
self.assertTrue(isinstance(d, dict))
def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEqual(d.key, 'value')
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value')
def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError):
value = d.empty
#以test開頭的方法就是測試方法,不以test開頭的方法不被認爲是測試方法,測試的時候不會被執行。
if __name__ == '__main__':
unittest.main()
直接在jupyter notebook裏面運行會報錯,正確的做法是編輯倆個.py文件,然後在運行…test.py那個即可
具體參考:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191629979802b566644aa84656b50cd484ec4a7838000
huxiang@shenyong-Opt790:~/work/test
huxiang@shenyong-Opt790:~/work/test$ python mydict_test.py
EEEEE
ERROR: test_attr (main.TestDict)
Traceback (most recent call last):
File “mydict_test.py”, line 17, in test_attr
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)
======================================================================
ERROR: test_attrerror (main.TestDict)
Traceback (most recent call last):
File “mydict_test.py”, line 28, in test_attrerror
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)
======================================================================
ERROR: test_init (main.TestDict)
Traceback (most recent call last):
File “mydict_test.py”, line 6, in test_init
d = Dict(a=1, b=’test’)
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)
======================================================================
ERROR: test_key (main.TestDict)
Traceback (most recent call last):
File “mydict_test.py”, line 12, in test_key
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)
======================================================================
ERROR: test_keyerror (main.TestDict)
Traceback (most recent call last):
File “mydict_test.py”, line 23, in test_keyerror
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)
Ran 5 tests in 0.001s
FAILED (errors=5)
4 文檔測試
# mydict2.py
class Dict(dict):
'''
Simple dict but also support access as x.y style.
>>> d1 = Dict()
>>> d1['x'] = 100
>>> d1.x
100
>>> d1.y = 200
>>> d1['y']
200
>>> d2 = Dict(a=1, b=2, c='3')
>>> d2.c
'3'
>>> d2['empty']
Traceback (most recent call last):
...
KeyError: 'empty'
>>> d2.empty
Traceback (most recent call last):
...
AttributeError: 'Dict' object has no attribute 'empty'
'''
def __init__(self, **kw):
super(Dict, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
if __name__=='__main__':
import doctest
doctest.testmod()
運行什麼結果也沒有,代表代碼是正確的,如果把getattr註釋掉,則會報錯:
# mydict2.py
class Dict(dict):
'''
Simple dict but also support access as x.y style.
>>> d1 = Dict()
>>> d1['x'] = 100
>>> d1.x
100
>>> d1.y = 200
>>> d1['y']
200
>>> d2 = Dict(a=1, b=2, c='3')
>>> d2.c
'3'
>>> d2['empty']
Traceback (most recent call last):
...
KeyError: 'empty'
>>> d2.empty
Traceback (most recent call last):
...
AttributeError: 'Dict' object has no attribute 'empty'
'''
def __init__(self, **kw):
super(Dict, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
# def __setattr__(self, key, value):
# self[key] = value
if __name__=='__main__':
import doctest
doctest.testmod()
**********************************************************************
File "__main__", line ?, in __main__.Dict
Failed example:
d1['y']
Exception raised:
Traceback (most recent call last):
File "/home/huxiang/anaconda2/envs/tensorflow/lib/python2.7/doctest.py", line 1315, in __run
compileflags, 1) in test.globs
File "<doctest __main__.Dict[4]>", line 1, in <module>
d1['y']
KeyError: 'y'
**********************************************************************
1 items had failures:
1 of 9 in __main__.Dict
***Test Failed*** 1 failures.