python其它,专栏总目录:
高级语言通常都内置了一套try...except...finally...的错误处理机制。
1、try
1.1、try的机制
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')
当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。
上面的代码在计算10 / 0时会产生一个除法运算错误,输出:
try...
except: division by zero
finally...
END
注:若所有的except都未正确捕获到异常,则错误最后被python解释器捕获。
1.2、深入讨论
1)try...else
如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句,出错则不执行else:
try:
print('try...')
r = 10 / int('1')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
没有错误时,执行try:->else:->finally:输出:
try...
result: 10.0
no error!
finally...
END
2)基类错误类型会屏蔽自类
Python的错误其实也是class,所有的错误类型都继承自BaseException,基类会捕获其所有子类错误类型。比如:
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeError as e:
print('UnicodeError')
按照顺序捕获,第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。
对于try...except语句,最好的写法是在最后添加一个公共基类的异常捕获,以确保try可以捕获所有异常。
except Exception as e:
print('Exception:', e)
Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:
https://docs.python.org/3/library/exceptions.html#exception-hierarchy
3)跨越多层调用
使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用bar(),bar()调用foo(),结果foo()出错了,这时,只要main()捕获到了,就可以处理:
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)
finally:
print('finally...')
也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。
2、记录错误
Python内置的logging模块可以非常容易地记录错误信息:
import logging
try:
...
except Exception as e:
logging.exception(e)
同样是出错,但程序打印完错误信息后会继续执行,并正常退出,通过配置,logging还可以把错误记录到日志文件里,方便事后排查。
3、断言
凡是用print()来辅助查看的地方,都可以用断言(assert)来替代:
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。如果断言失败,assert语句本身就会抛出AssertionError:
$ python err.py
Traceback (most recent call last):
...
AssertionError: n is zero!
程序中如果到处充斥着assert,和print()相比也好不到哪去。不过,启动Python解释器时可以用-O参数来关闭assert:
$ python -O err.py
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
注意:断言的开关“-O”是英文大写字母O,不是数字0。关闭后,你可以把所有的assert语句当成pass来看。