笔记整理于廖雪峰官网和菜鸟教程
错误处理
异常:
Python脚本发生异常时需要捕获处理,否则程序会中止执行。
异常类型:
https://www.runoob.com/python/python-exceptions.html
try…except…else
- 描述
检测try语块中的错误,except捕获异常信息并处理。
(个人理解)当开始一个try语句后,如果能except错误则继续执行后面的代码,如果没有匹配的except则报错中止。
try:
1、try语句异常,跳回try匹配except,异常处理结束则通过try语句。
2、try语句异常,没有匹配except,异常被递交到上层的try,将结束程序打印错误。
3、try语句没有异常,执行else,通过try语句。
4、无论有无异常,如果存在finally语句,退出try总会执行finally。
except:
1、如果第一个except错误是第二个的父类,那么当出现第二个except对应错误的时候,将被第一个except捕获而不会进行第二个。
2、一个except可以对应多个异常
except(Exception1[, Exception2[,…ExceptionN]]]):
发生以上多个异常中的一个,执行这块代码
a=0
try:
print('try...')
r = 10 / int(a)
print('result:', r)
#如果没有对应错误的except语句,则返回上层调用报错,终止程序,不会输出print('END')
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
finally:#无论try中是否有错误都会运行finally
print('finally...')
print('END')
- 语法
try:
<语句>
except 异常名1:
<语句>#引发异常1的处理
except 异常名2:
<语句>#引发异常2的处理
else:
<语句>#如果没有异常发生
finally:
<语句>#退出try总会执行
调用栈
如果错误不能被捕获,就会一直上抛直到被Python解释器捕获。
当程序运行出错一定要分析错误的调用栈信息来定位错误位置。
# err.py:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
main()
执行结果:
错误是因为调用main(),原因追溯到第9行的bar(‘0’),第6行的foo(s)*2,第三行的return 10/int(s),根据错误类型ZeroDivisionError,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。
$ python3 err.py
Traceback (most recent call last):
File “err.py”, line 11, in
main()
File “err.py”, line 9, in main
bar(‘0’)
File “err.py”, line 6, in bar
return foo(s) * 2
File “err.py”, line 3, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
logging记录错误
使用logging模块,把错误堆栈打印出来记录错误信息,同时继续执行错误。
imort logging
在try语句中
except Exception(错误类型) as e:
logging.exception(e)(打印错误栈)
# 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')
如果不使用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:
print('error:',e)
main()
print('END')
#输出
#error: division by zero
#END
raise抛出异常
- 定义异常
raise Exception(“Invalid level!”, level)
错误是class的一个实例,可以通过定义错误类,用raise抛出错误实例。
# err_raise.pyclass FooError(ValueError):
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n
foo('0')
执行错误代码后,将追踪到自定义的错误FooError的错误。
$ python3 err_raise.py
Traceback (most recent call last):
File “err_throw.py”, line 11, in
foo(‘0’)
File “err_throw.py”, line 8, in foo
raise FooError(‘invalid value: %s’ % s)
main.FooError: invalid value: 0
- 抛出异常
对比以下两段代码,用except捕获错误后,通过raise抛出错误。捕获错误的目的是记录错误,抛出错误是一直向上抛出错误,最终进行处理。
# 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:
print('error:',e)
main()
print('END')
#输出
#error: division by zero
#END
# 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()
print('end err_reraise')
- 练习
运行下面的代码,根据异常信息进行分析,定位出错误源头,并修复:
from functools import reduce
def str2num(s):
return int(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()
错误信息
100 + 200 + 345 = 645
Traceback (most recent call last):
File “C:\Users\Violette\AppData\Local\Temp\learn_python_4a90wt1w_py\test_6.py”, line 18, in
main()
File “C:\Users\Violette\AppData\Local\Temp\learn_python_4a90wt1w_py\test_6.py”, line 15, in main
r = calc(‘99 + 88 + 7.6’)
File “C:\Users\Violette\AppData\Local\Temp\learn_python_4a90wt1w_py\test_6.py”, line 10, in calc
return reduce(lambda acc, x: acc + x, ns)
File “C:\Users\Violette\AppData\Local\Temp\learn_python_4a90wt1w_py\test_6.py”, line 5, in str2num
return int(s) ValueError: invalid literal for int() with base 10: ’ 7.6’
修改:
本来向直接把int(s)变成float(s),但这样整数的str也将得到float的结果。
看了评论发现,可以这里应用try,将int的错误except生成float。
如果需要完善就是将不能str2num的错误通过except来rasie。
from functools import reduce
def str2num(s):
try:
return int(s)
except:
return float(s)
#def str2num(s):
# return int(s)#错误7.6
#更改为 return float(s)
def calc(exp):
ss = exp.split('+')
ns = map(str2num, ss)
return reduce(lambda acc, x: acc + x, ns)# 错误in str2num return int(s)
def main():
r = calc('100 + 200 + 345')
print('100 + 200 + 345 =', r)
r = calc('99 + 88 + 7.6')#错误in calc return reduce(lambda acc, x: acc + x, ns)
print('99 + 88 + 7.6 =', r)
main()