try
高级语言通常都内置了一套try...except...finally...的错误处理机制
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('execpt:', e)
finally:
print('finally...')
print('END')
人为某些代码可能会出错时,可以使用try来运行 这段代码,如果出错,后续代码不会继续执行,而直接至错误处理代码execpt语句块,当execpt执行后,如果有finally语句块,则执行finally
多种错误类, 由不同的except来处理,使用多个的execpt来捕获不同类型的错误
try:
print('try...')
r = 10 / int('a')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
finally:
print('finally...')
print('END')
int()函数可能会抛出ValueError,所以一个execpt捕获,另一个execpt捕获ZeroDivisionError,如果没有报错,可以在except语句块后加一个else,当没有错误发生时,会执行else语句
try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeDecodeError as e:
print("UnicodeDecodeError")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-9-ab31300112cb> in <module>()
1 try:
----> 2 foo()
3 except ValueError as e:
4 print('ValueError')
5 except UnicodeDecodeError as e:
NameError: name 'foo' is not defined
第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。
调用栈
记录错误
内置模块logging可以很简单的记录错误信息
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:division by zero
Traceback (most recent call last):
File "<ipython-input-11-cc27997fe30e>", line 11, in main
bar('0')
File "<ipython-input-11-cc27997fe30e>", line 7, in bar
return foo(s) * 2
File "<ipython-input-11-cc27997fe30e>", line 4, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
END
通过配置,logging还可以把错误记录到日志文件里,方便事后排查。
抛出错误 raise
错误是一个class,捕获错误就是捕获该class的一个实例
如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用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-13-ace543256765> in <module>()
7 raise FooError('invalid value: %s' % s)
8 return 10 / n
----> 9 foo('0')
<ipython-input-13-ace543256765> in foo(s)
5 n = int(s)
6 if n == 0:
----> 7 raise FooError('invalid value: %s' % s)
8 return 10 / n
9 foo('0')
FooError: invalid value: 0
练习
运行下面的代码,根据异常信息进行分析,定位出错误源头,并修复:
from functools import reduce
def str2num(s):
return int(s) ## # 如果写int("7.0")就会错误,因为python假设需要进行int转型的字符串仅仅包含数字,这时候用round(float("1.0"))就ok了。
def calc(exp):
ss = exp.split('+')
ns = map(str2num, ss)
return reduce(lambda acc, x: acc + x, ns)
def main():
r = calc('100 + 200 + 345')
print('100 + 200 + 345 =', r)
r = calc('99 + 88 + 7.6')
print('99 + 88 + 7.6 =', r)
main()
100 + 200 + 345 = 645
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-15-ad8040b068b8> in <module>()
15 print('99 + 88 + 7.6 =', r)
16
---> 17 main()
<ipython-input-15-ad8040b068b8> in main()
12 r = calc('100 + 200 + 345')
13 print('100 + 200 + 345 =', r)
---> 14 r = calc('99 + 88 + 7.6')
15 print('99 + 88 + 7.6 =', r)
16
<ipython-input-15-ad8040b068b8> in calc(exp)
7 ss = exp.split('+')
8 ns = map(str2num, ss)
----> 9 return reduce(lambda acc, x: acc + x, ns)
10
11 def main():
<ipython-input-15-ad8040b068b8> in str2num(s)
2
3 def str2num(s):
----> 4 return int(s)
5
6 def calc(exp):
ValueError: invalid literal for int() with base 10: ' 7.6'
# 修复后
from functools import reduce
def str2num(s):
return round(float(s))
def calc(exp):
ss = exp.split('+')
ns = map(str2num, ss)
return reduce(lambda acc, x: acc + x, ns)
def main():
r = calc('100 + 200 + 345')
print('100 + 200 + 345 =', r)
r = calc('99 + 88 + 7.6')
print('99 + 88 + 7.6 =', r)
main()
# 如果写int("7.0")就会错误,因为python假设需要进行int转型的字符串仅仅包含数字,这时候用round(float("1.0"))就ok了。
100 + 200 + 345 = 645
99 + 88 + 7.6 = 195