python自学之《21天学通Python》——错误、异常和程序调试

第7章 错误、异常和程序调试

7.1 语法错误
语法错误是所有编程语言中都存在的一种常见错误,即程序的写法不符合编程语言的规定。常见的语法错误有:
1.拼写错误
即Python语言中的关键字写错,变量名、函数名拼写错误等。关键字拼写错误时会提示SyntaxError(语法错误),而变量名、函数名拼写错误会在运行时给出NameError的错误提示
2.脚本程序不符合Python的语法规范
例如如少了括号,冒号等符号,以及表达式书写错误等。
3.缩进错误
因为Python语法规定,以缩进作为程序的语法之一,这应该是Python语言独特的一面。一般来说Python标准的缩进是以4个空格作为一个缩进。当然,你可以依据自己的习惯,使用Tab也可以。但同一个程序或项目中应该统一使用同一种缩进风格。
7.2 异常的处理
异常是Python程序在运行过程中引发的错误。如果程序中引发了未进行处理的异常,脚本就会由于异常而终止运行。只有在程序中捕获这些异常,并进行相关的处理,才能使程序不会中断运行。
7.2.1异常处理的基本语法
Python中使用try语句来处理异常,和Python中其他语句一样,try语句也要使用缩进结构,try语句也有一个可选的else语句块。一般的try语句基本形式如下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


>>> def testTry(index, flag=False):
...     stulst= ["John", "Jenny", "Tom"]
...     if flag:
...         try:
...             astu = stulst[index]
...         except IndexError:
...             print("IndexError")
...         return "Try Test Finished!"
...     else:
...         astu = stulst[index]
...         return "No Try Test Finished!"
... 
>>> print("Right params testing start...")
Right params testing start...
>>> print(testTry(1, True))
Try Test Finished!
>>> print(testTry(1, False))
No Try Test Finished!
>>> print("Error params testing start...")
Error params testing start...
>>> print(testTry(4, True))
IndexError
Try Test Finished!
>>> print(testTry(4, False))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in testTry
IndexError: list index out of range

在这里插入图片描述
在这里插入图片描述

7.2.2 Python主要的内置异常及其处理
在这里插入图片描述
>>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

except语句主要有以下几种用法。
except:#捕获所有异常;
except <异常名>:#捕获指定异常;
except (异常名1,异常名2):#捕获异常名1或者异常名2;
except <异常名> as <数据>:#捕获指定异常及其附加的数据;
except(异常名1,异常名2)as <数据>:#捕获异常名1或者异常名2及异常的附加数据。
在这里插入图片描述

>>> def testTryAll(index,i):
...     stulst = ["John", "Jenny", "Tom"]
...     try:
...         print(len(stulst[index]) / i)
...     except:
...         print("Error!")
... 
>>> print('Try all...Right')
Try all...Right
>>> testTryAll(1,2)
2.5
>>> print('Try all...one Error')
Try all...one Error
>>> testTryAll(1,0)
Error!
>>> print('Try all...two Error')
Try all...two Error
>>> testTryAll(4,0)
Error!
>>> 

一般情况下,应在程序中指明所要捕获的异常,而不是简单地捕获所有异常
7.3 手工抛出异常
上一节程序中,所有的异常都是在程序运行中出现了错误而引发的异常,程序员还可以在Python程序中使用raise语句来引发指定的异常,并向异常传递数据。为了程序的需要,程序员还可以自定义新的异常类型,例如对用户
输入文本的长度有要求,则可以使用raise引发异常,以确保文本输入的长度符合要求。
7.3.1 用raise手工抛出异常
raise 异常名
raise 异常名,附加数据
raise 类名
使用raise可以抛出各种预定的异常,即使程序在运行时根本不会引发该异常

>>> def testRaise():
...     for i in range(5):
...         if i == 2:
...             raise NameError
...         print(i)
...     print('end...')
... 
>>> testRaise()
0
1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in testRaise
NameError

>>> def testRaise2():
...     for i in range(5):
...         try:
...             if i == 2:
...                 raise NameError
...         except NameError:
...             print('Raise a NameError!')
...         print(i)
...     print('end...')
... 
>>> testRaise2()
0
1
Raise a NameError!
2
3
4
end...

7.3.2 assert语句
assert语句的一般形式如下:assert <条件测试>, <异常附加数据> #其中异常附加数据是可选的
assert语句是简化的raise语句,它引发异常的前提是其后面的条件测试为假
在这里插入图片描述


>>> def testAssert():
...     for i in range(3):
...         try:
...             assert i < 2
...         except AssertionError:
...             print('Raise a AssertionError!')
...         print(i)
...     print('end...')
... 
>>> testAssert()
0
1
Raise a AssertionError!
2
end...

assert语句一般用于在程序开发时测试代码的有效性。比如某个变量的值必须在一定范围内,而运行时得到的值不符合要求,则引发该异常,对开发者予以提示。所以一般在程序开发中,不去捕获这个异常,而是让它中断程序。原因是程序中已经出现了问题,不应继续运行。
assert语句一般用于在程序开发时测试代码的有效性。比如某个变量的值必须在一定范围内,而运行时得到的值不符合要求,则引发该异常,对开发者予以提示。所以一般在程序开发中,不去捕获这个异常,而是让它中断程序。原因是程序中已经出现了问题,不应继续运行。assert语句并不是总是运行的,只有Python内置的一个特殊变量__debug__为True时才运行。要关闭程序中的assert语句就使用python-O(短画线,后接大写字母O)来运行程序。
7.3.3 自定义异常类
在Python中定义异常类不用从基础完全自己定义,只要通过继承Exception类来创建自己的异常类。异常类的定义和其他类没有区别,最简单的自定义异常类甚至可以只继承Exception类,类体为pass如:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
7.4 用pdb调试程序
Python解释器可以发现程序中的语法错误,在试运行时会中断执行并给出提示。但是程序中逻辑上的错误,或其他非语法错误不会被发现。虽然程序能够正常运行,但是运行后得不到预想的结果,这就要对程序进行调试。调试程序可以使用Python自带的pdb模块,其功能有设置断点、单步执行、查看变量等。它可以用命令行参数的形式启动,也可以通过导入模块使用。常用的pdb模块的函数可以分为以下几类:
pdb模块中的调试语句块的函数及参数原型为
run( statement[, globals[, locals]])
statement 要调试的语句块,以字符串的形式表示;
globals 可选参数,设置statement运行的全局环境变量;
locals 可选参数,设置statement运行的局部环境变量。

>>> pdb.run("""
... for i in range(3):
...     print(i)
... """)
> <string>(2)<module>()
(Pdb) h

Documented commands (type help <topic>):
========================================
EOF    c          d        h         list      q        rv       undisplay
a      cl         debug    help      ll        quit     s        unt      
alias  clear      disable  ignore    longlist  r        source   until    
args   commands   display  interact  n         restart  step     up       
b      condition  down     j         next      return   tbreak   w        
break  cont       enable   jump      p         retval   u        whatis   
bt     continue   exit     l         pp        run      unalias  where    

Miscellaneous help topics:
==========================
exec  pdb

(Pdb) n

> <string>(3)<module>()
(Pdb) print(r)
*** NameError: name 'r' is not defined
(Pdb) r
0
1
2
--Return--
> <string>(2)<module>()->None
(Pdb) 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.4.2 调试函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


>>> import pdb
>>> def sum(maxint):
...     s = 0
...     for i in range(maxint):
...         s += i
...     return s
... 
>>> pdb.runcall(sum,10)
> <stdin>(2)sum()
(Pdb) n
> <stdin>(3)sum()
(Pdb) n
> <stdin>(4)sum()
(Pdb) s=0
> <stdin>(3)sum()
(Pdb) s += i
> <stdin>(4)sum()
(Pdb) 

7.5 测试程序
当编写完程序,并排除了语法错误之后,虽然程序可以运行,但程序的运行结果和期待的可能也会不一致。这说明程序中可能会有bug,即程序的逻辑错误。发现和清除这类错误就要对程序进行测试,最好的方法就是使用测试驱动的开发(TDD)。对程序进行测试种类包括可用性测试、功能测试、单元测试及整合测试等。
Python标准库中,就有doctest和unittest模块可用于测试。本节主要讲解采用Python标准模块doctest中的testmod函数和testfile函数进行简单的单元测试。
7.5.1 用testmod函数测试
用testmod函数进行单元测试,就要将测试用例写入程序的docstring中,然后可以用两种方法进行测试。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意>>> grade(100)语句中>>>后要有一个空格
在这里插入图片描述
7.5.2 用testfile函数测试
上一节中的测试函数要求测试用例是写在程序文件之中的docstring中的。如果因为某种原因,你不想或不能将测试用例写入程序文件中,就可以应用testfile函数进行测试。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
7.6 小结
本章主要介绍在Python语言中的错误、异常和程序的简单调试。首先介绍了基本语法错误、异常的基本概念,以及如何用代码捕获和引发异常及自定义异常的方法。其次介绍了使用Python的内置模块pdb调试Python程序。最后讲解运用标准库doctest进行简单的单元测试。通过对本章的学习,读者能够掌握引发异常、捕获和处理异常及自定义异常;会使用pdb模块进行基本的程序调试;能用doctest模块对程序进行基本的单元测试。
7.7 本章习题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值