python函数异常返回 python异常处理方法( 二 )


bar("0")except Exception as e:print("Error:", e)finally:print("finally...")
也就是说 , 不需要在每个可能出错的地方去捕获异常,只要在合适的层次去捕获就可以了 。
这样一来,就大大减少了写 try...except...finally的麻烦 。
二、调用堆栈
如果错误没有被捕获,他就会一直往上抛 , 最后被python解释器捕获,打印一个错误信息,然后程序退出 。def foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():
bar("0")
main()
执行结果为:
Traceback (most recent call last):
File "C:/Python36/test.py", line 10, in module
main()
File "C:/Python36/test.py", line 8, in main
bar("0")
File "C:/Python36/test.py", line 5, in barreturn foo(s) * 2
File "C:/Python36/test.py", line 2, in fooreturn 10 / int(s)
ZeroDivisionError: division by zero
出错并不可怕 , 可怕的时不知道哪里出错了 。解读错误信息时定位错误的关键 。
我们从上往下可以看到整个错误的调用函数链 。
错误第一行:
Traceback (most recent call last):
这告诉我们的是错误的跟踪信息 。
File "C:/Python36/test.py", line 10, inmodule main()
说明调用main()出错了,在代码文件test.py中第10行,但是原因是第8行:
File"C:/Python36/test.py", line8, in main
bar("0")
调用bar("0")出错了 , 在代码文件test.py中第8行,但原因是第5行:
File"C:/Python36/test.py", line5, in barreturn foo(s) * 2调用return foo(s) * 2时出错了,在test.py中第5行,但原因是第2行
File "C:/Python36/test.py", line 2, in fooreturn 10 / int(s)
ZeroDivisionError: division by zero
这时我们找到了源头,原来在第2行调用return 10 / int(s)出错了,错误为ZeroDivisionError
三、记录错误
如果不捕获错误,自然可以让python解释器来打印出错误堆栈 , 但是程序也被结束了 。
既然我们能捕获错误 , 就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去 。
python内置的logging模块可以非常容易地记录错误信息:import loggingdef foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def 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 "C:/Python36/test.py", line 12, in main
bar("0")
File "C:/Python36/test.py", line 8, in barreturn foo(s) * 2
File "C:/Python36/test.py", line 5, in fooreturn 10 / int(s)
ZeroDivisionError: division by zero
END
同样是出错 , 但程序打印完错误信息后会继续执行,并正常退出 。
通过配置,logging还可以把错误记录到日志文件里 , 方便事后排查 。
四、抛出错误
因为错误是class,捕获一个错误就是捕获到该class的一个实例 。
因此,错误并不是凭空产生的,而是有意创建并抛出的 。
python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误 。
如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系 , 然后用raise语句抛出一个错误的实例:class FooError(ValueError):passdef foo(s):
n =int(s)if n == 0:raise FooError("invalid value: %s" % s)return 10 / n
foo("0")
输出结果:
Traceback (most recent call last):
File "C:/Python36/test.py", line 10, in module
foo("0")
File "C:/Python36/test.py", line 7, in fooraise FooError("invalid value: %s" % s)
FooError: invalid value: 0
只有在必要的时候才定义我们自己的错误类型 。
如果可以选择python已有的内置错误类型(比如ValueError, TypeError),尽量使用python内置的错误类型 。

推荐阅读