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
vimydict.pyhuxiang@shenyong−Opt790: /work/test
vi mydict_test.py
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.