笔记整理于廖雪峰官网和菜鸟教程

错误处理

异常:
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')

python 打印详细错误 python try 打印错误_堆栈

如果不使用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')

python 打印详细错误 python try 打印错误_抛出异常_02

  • 练习
    运行下面的代码,根据异常信息进行分析,定位出错误源头,并修复:
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()