想喝猪肝汤

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

错误处理

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)

in ()
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,因为UnicodeErrorValueError的子类,如果有,也被第一个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 "", line 11, in main
bar('0')
File "", line 7, in bar
return foo(s) * 2
File "", 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)

in ()
7 raise FooError('invalid value: %s' % s)
8 return 10 / n
----> 9 foo('0')

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)

in ()
15 print('99 + 88 + 7.6 =', r)
16
---> 17 main()

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

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():

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

posted on 2018-10-31 15:08  想喝猪肝汤  阅读(226)  评论(0)    收藏  举报