python错误和调试

Posted bfcs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python错误和调试相关的知识,希望对你有一定的参考价值。

在程序运行过程中,总会遇到各种各样的错误。

有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的。

有的错误是用户输入造成的,比如让用户输入email地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。

还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了。这类错误也称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。

错误处理

try...except...finally

当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

 1 #!/usr/bin/python3
 2 
 3 try:
 4     r = 10 / 0
 5     print (result:,r)
 6 except ZeroDivisionError as e:
 7     print (除数不能为零 ,e)
 8 finally:
 9     print (--------)
10 print (END)

技术图片

如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

 1 #!/usr/bin/python3
 2 
 3 try:
 4     r = 10 / int(2)
 5     print (result:,r)
 6 except ZeroDivisionError as e:
 7     print (除数不能为零 , e)
 8 except ValueError as e:   #int()可能抛出ValueError
 9     print (ValueError, e)
10 else:
11     print (No Error!)
12 finally:
13     print (--------)
14 print (END)

技术图片

Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。

常见的错误类型和继承关系  https://docs.python.org/3/library/exceptions.html#exception-hierarchy

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo()foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理:

 1 #!/usr/bin/python3
 2 
 3 def foo(s):
 4     return 10 / s
 5 
 6 def bar(s):
 7     return foo(s)*2
 8 
 9 def main():
10     try:
11         bar(0)
12     except Exception as e:
13         print (Error, e)
14     finally:
15         print (---------------)
16         
17 main()

技术图片

 

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。

 

 1 #!/usr/bin/python3
 2 
 3 def foo(s):
 4     return 10 / int(s)
 5 
 6 def bar(s):
 7     return foo(s)*2
 8 
 9 def main():
10     bar(0)
11 
12 main()

技术图片

可以看到,问题的源头追溯到第四行代码,第四行代码,除数不能为零

 

记录错误

捕获错误,打印错误堆栈,同时让程序继续执行

 1 #!/usr/bin/python3
 2 
 3 import logging
 4 
 5 def foo(s):
 6     return 10 / int(s)
 7 
 8 def bar(s):
 9     return foo(s)*2
10 
11 def main():
12     try:
13         bar(0)
14     except Exception as e:
15         logging.exception(e)
16 
17 main()
18 print(END)

同样是出错,但程序打印完错误信息后会继续执行,并正常退出:

技术图片

 

抛出错误

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

 1 #!/usr/bin/python3
 2 
 3 class FooError(ValueError):   #选择好继承关系
 4     pass
 5 
 6 def foo(s):
 7     n = int(s)
 8     if n == 0:
 9         raise FooError(无效的值:%s % s)
10     return 10 / n
11     
12 foo(0)

技术图片

只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueErrorTypeError),尽量使用Python内置的错误类型。

 

调试

程序能一次写完并正常运行的概率很小,总会有各种各样的bug需要修正。有的bug很简单,看看错误信息就知道,有的bug很复杂,我们需要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,因此,需要一整套调试程序的手段来修复bug。

断言   assert

把可能有问题的变量打印出来看看

 1 #!/usr/bin/python3
 2 
 3 def foo(s):
 4     n = int(s)
 5     assert n != 0, n is zero!
 6     return 10 / n
 7 
 8 def main():
 9     foo(0)
10 
11 main()

assert的意思是,表达式 n != 0应该是True,True的话继续执行,否则,根据程序运行的逻辑,后面的代码肯定会出错。

如果断言失败,assert语句本身就会抛出AssertionError

技术图片

logging

assert比,logging不会抛出错误,而且可以输出到文件,可指定记录信息的级别(低到高:debug  info  warning  error)当指定 level = WARNING后 debug和info就不起作用,即可以输出不同级别的信息

1 #!/usr/bin/python3
2 
3 import logging
4 logging.basicConfig(level = logging.INFO)
5 
6 s = 0
7 n = int(s)
8 logging.info(n = %d % n)
9 print (10 / n)

技术图片

 

pdb

-m pdb  让程序以单步方式运行,可以随时查看运行状态。

1 #!/usr/bin/python3
2 
3 s = 0
4 n = int(s)
5 print (10 / n)

技术图片

l  查看代码  n  单步  p 变量名    查看变量  q结束调试

 

以上是关于python错误和调试的主要内容,如果未能解决你的问题,请参考以下文章

Python 自动化 - 浏览器chrome打开F12开发者工具自动Paused in debugger调试导致无法查看网站资源问题原因及解决方法,javascript反调试问题处理实例演示(代码片段

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

python调试之pdb调试工具

python调试:pdb基本用法(转)

python,错误调试和测试

方便调试使用的代码片段