想喝猪肝汤

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

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,因为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 "<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
posted on 2018-10-31 15:08  想喝猪肝汤  阅读(214)  评论(0)    收藏  举报