Python学习笔记九 错误、调试
参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
一、错误处理
Python提供了一套try...except...finally...的错误处理机制,先看一个示例:
try: print("try...") r=10/0 print("result:",r) except ZeroDivisionError as e: print("except:",e) finally: print("finally...") print('END')
执行结果如下:
try... except: division by zero finally... END
try语句后面跟的是我们认为可能出错的代码,如果真的出错了就会停止执行其中的代码并转向except语句;无论是否出错最后都会执行finally语句的代码。
这里因为出错的是除数是0这个错误,所以在except中直接写定了该中错误的类型“ZeroDivisionError”;但有时候我们不明确到底会错误类型,所以可以通过多个except去处理:
try: print("try...") r=10/int('a') print("result:",r) except ValueError as e: #处理值类型错误 print("ValueError:",e) except ZeroDivisionError as e:#处理除数为0错误 print("except:",e) finally: print("finally...") print('END')
如果没有错误发生,我们也可以在try...except...后面跟一个else语句,这里的代码可以在没有错误发生时运行。
try: print("try...") r=10/int('11') print("result:",r) except ValueError as e: #处理值类型错误 print("ValueError:",e) except ZeroDivisionError as e:#处理除数为0错误 print("except:",e) else: print('no error!') finally: print("finally...") print('END')
使用try...except语句还有一个好处,就是跨越多层调用,假设有三个函数: foo() bar() main(),依此为调用关系,如果foo()运行时候出错了,我们在调用环节就可以对其进行处理。
def foo(s): return 10/int(s) def bar(s): return foo(s)*2 def main(): try: bar('0') except Exception as e: print("Exception:",e) finally: print('finally') main() #输出: Exception: division by zero finally
可以看出,我们不需要在每个可能出错的地方去捕获并处理错误,在合适的层次去处理就可以了。
*调用栈
如果错误没有被捕获,就会一直往上一层抛出,如果一直没有被捕获处理,最后将被解释器捕获,并打印一个错误信息。
def foo(s): return 10/int(s) def bar(s): return foo(s)*2 def main(): bar('0') main()
执行结果如下:
Traceback (most recent call last): #错误追朔 File "...", line 10, in <module> #首先出错的是第10行的main() main() File "...", line 8, in main #但上面出错的原因在第8行bar('0') bar('0') File "...", line 5, in bar #但上面出错的原因在第5行return foo(s)*2 return foo(s)*2 File "...", line 2, in foo #但上面出错的原因在第2行 return 10/int(s)
return 10/int(s)
ZeroDivisionError: division by zero #这里已经不再追朔,而是已经找到错误源头,直接给出错误类型,是一个除数为0错误
上面的代码在出错后已经停止运行了,并且给出了追朔过程及错误信息。既然Python的traceback可以追朔出错原因,那它也提供了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!")
二、调试
(一)断言(assert)
对于可能出错的地方都可以插入assert语句分析测试:
def foo(s): n=int(s) assert n!=0,'n is zero!' return 10/n def main(): foo('0') main()
上述代码中增加了“assert n!=0,'n is zero!'”,表示:断言n必须不为0,否则报错信息。断言失败则会抛出AssertError:
Traceback (most recent call last): 。。。 AssertionError: n is zero!
(二)logging
和assert相比,logging不会抛出错误,而且可以输出错误信息到文本
import logging logging.basicConfig(level=logging.INFO) s='0' n=int(s) logging.info('n=%d',n) #logging的用法同样是放到可能出错的代码处 print(10/n)