zoukankan      html  css  js  c++  java
  • 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 NameError    #尝试访问一个未声明的变量(没有初始化)
     2 ZeroDivisionError    #除数为零
     3 SyntaxError        #解释器语法错误,唯一不是在运行时发生的异常,在编译时发生,它代表Python代码中有一个不正确的结构
     4 IndexError    #请求的索引超出序列范围
     5 KeyError    #请求一个不存在的字典键
     6 IOError        #输入输出错误:(1)打开一个不存在的文件(2)文件写入时,操作和模式不匹配(3)权限问题导致
     7 TypeError    #类型错误,如'2'+2,类型不相同不能相加
     8 AttributeError    #尝试访问未知的对象属性,即对象根本没有定义这一属性却尝试访问它
     9 StopIteration    #迭代器没有更多的值
    10 RuntimeError    #一般的运行时错误
    11 SystemError        #一般的解释器系统错误
    12 ValueError        #传入无效的参数

    调用栈

    如果错误没有被捕获,它就会一直往上抛,最后被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写第一个网页
    科学计算和可视化
    类和正则表达(自动更正,和代数运算)
    图片处理
    jieba
    汉诺塔问题
    Python核心编程(第二版)第十章习题答案
    python官方文档之open()函数的翻译
    python打开文件时提示“File was loaded in the wrong encoding:’UTF-8”根因调查
  • 原文地址:https://www.cnblogs.com/bfcs/p/10778151.html
Copyright © 2011-2022 走看看