一、异常

当Python解释器遇到一个无法预期的程序行为的时候,就会输出一个异常(exception),eg:除以零或者打开不存在的文件等。当Python解释器遇到异常情况的时候,它会停止程序的运行,然后显示一个追踪(traceback)信息。

二、常见错误和异常

2.1 语法错误(SyntaxError)

2.1.1 缺少冒号

在if、elif、else、for、while、class、def声明末尾都需要添加“:”,如果没有添加就会出现 SyntaxError: invalid syntax 的错误

2.1.2 将赋值运算符=与比较运算符== 混淆

2.1.3 在字符串首尾没有加引号

2.1.4 使用关键字作为变量名

Pytho关键字不能作为变量名。

  1. import keyword
  2. print(keyword.kwlist)
  3. ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

2.1.5 误用自增或自减运算符

在python中没有自增(++)和自减(—)运算符。

2.1.6 代码结构的缩进错误

  1. if __name__ == "__main__"
  2. coor = coordination()
  3. coor.position()
  4. ##结果
  5. if __name__ == "__main__"
  6. ^
  7. SyntaxError: invalid syntax
  8. ##缩进错误
  9. import keyword
  10. print(keyword.kwlist)
  11. ##结果
  12. print(keyword.kwlist)
  13. ^
  14. IndentationError: unexpected indent

2.2 除零错误(ZeroDivisionError)

  1. print(25/0)
  2. ##结果
  3. print(25/0)
  4. ZeroDivisionError: division by zero

2.3 变量名错误(NameError)

命令或程序中访问的变量未经定义而直接使用。

  1. print(numbers)
  2. ##结果
  3. print(numbers)
  4. NameError: name 'numbers' is not defined

2.4 操作类型错误(TypeError)

2.4.1 修改元组和字符串的值

元组和字符串的元素值是不能进行修改的,修改的话们就会提示错误

  1. ##修改元组的值
  2. aa = (100,220,300)
  3. aa[1]=300
  4. aa[1]=300
  5. TypeError: 'tuple' object does not support item assignment
  6. ##修改字符串的值
  7. aa ="千里黄云白日曛"
  8. aa[1]=1
  9. aa[1]=1
  10. TypeError: 'str' object does not support item assignment

2.4.2 连接字符串和非字符串

  1. aa ="千里黄云白日曛"
  2. list=[1,2,3,4]
  3. print(aa+list)
  4. ##结果
  5. print(aa+list)
  6. TypeError: can only concatenate str (not "list") to str

2.4.3 方法的第一个参数没有添加self参数

  1. class GS():
  2. def myMethod():
  3. print("这个")
  4. g = GS()
  5. g.myMethod()
  6. ##结果
  7. g.myMethod()
  8. TypeError: myMethod() takes 0 positional arguments but 1 was given

2.4.4 不符合表达式中运算符的运算规则或者函数参数类型的错误

  1. print(len(123456))
  2. ##结果
  3. TypeError: object of type 'int' has no len()

2.5 下标越界错误(IndexError)

请求的索引下标超过了序列的范围而造成的错误。

  1. a= [1,5,3,8,6,8]
  2. print(a[100])
  3. ##结果
  4. print(a[100])
  5. IndexError: list index out of range

2.6 打开文件错误(FileNotFoundError)

  1. fp= open("1.txt",'r+')
  2. FileNotFoundError: [Errno 2] No such file or directory: '1.txt'

三、内置异常

https://docs.python.org/3.7/library/exceptions.html#exception-hierarchy

  1. BaseException ##所有异常的基类
  2. +-- SystemExit ##Python解释器请求退出
  3. +-- KeyboardInterrupt ##用户执行中断,ctrl+c
  4. +-- GeneratorExit ##生成器发生异常通知退出
  5. +-- Exception ##常规错误的基类
  6. +-- StopIteration ##迭代器没有更多的值
  7. +-- StopAsyncIteration ## 必须由一个 asynchronous iterator 对象的 __anext__() 方法来引发以停止迭代操作
  8. +-- ArithmeticError ##所有数值计算错误的基类
  9. | +-- FloatingPointError ##浮点计算错误
  10. | +-- OverflowError ##数值运算超出最大限制
  11. | +-- ZeroDivisionError ##除零(或取模)错误
  12. +-- AssertionError ##断言语句失败,在assert语句运行失败的时候输出
  13. +-- AttributeError ##对象没有这个属性
  14. +-- BufferError ##当与缓冲区相关的操作无法执行时将被引发
  15. +-- EOFError ##没有内建输入,到达EOF标记
  16. +-- ImportError ##导入模块/对象失败
  17. | +-- ModuleNotFoundError ##模块未找到
  18. +-- LookupError ##无效数据查询的基类
  19. | +-- IndexError ##序列中没有此索引(index)
  20. | +-- KeyError ##映射中没有这个键
  21. +-- MemoryError ##内存溢出错误
  22. +-- NameError ##未命名/初始化对象(没有属性)
  23. | +-- UnboundLocalError ##访问未初始化的本地变量
  24. +-- OSError ##操作系统错误
  25. | +-- BlockingIOError ##当一个操作会被某个设置为非阻塞操作的对象(例如套接字)所阻塞时将被引发
  26. | +-- ChildProcessError ##当一个子进程上的操作失败时将被引发
  27. | +-- ConnectionError ##与连接相关问题的基类
  28. | | +-- BrokenPipeError ##当试图写入另一端已被关闭的管道,或是试图写入已关闭写入的套接字时将被引发
  29. | | +-- ConnectionAbortedError ##当连接尝试被对端中止时将被引发
  30. | | +-- ConnectionRefusedError ##当连接尝试被对端拒绝时将被引发
  31. | | +-- ConnectionResetError ##当连接被对端重置时将被引发
  32. | +-- FileExistsError ##当试图创建一个已存在的文件或目录时将被引发
  33. | +-- FileNotFoundError ## 当所请求的文件或目录不存在时将被引发
  34. | +-- InterruptedError ##当系统调用被输入信号中断时将被引发
  35. | +-- IsADirectoryError ##当请求对一个目录执行文件操作将被引发
  36. | +-- NotADirectoryError ##当请求对一个非目录对象执行目录操作时将被引发
  37. | +-- PermissionError ##当在没有足够操作权限的情况下试图执行某个操作时将被引发
  38. | +-- ProcessLookupError ## 当给定的进程不存在时将被引发
  39. | +-- TimeoutError ## 当系统调用超时的时候被引发
  40. +-- ReferenceError ##弱引用(weak reference)试图访问已经垃圾回收的对象
  41. +-- RuntimeError ##一般的运行时错误
  42. | +-- NotImplementedError ##尚未实现的方法
  43. | +-- RecursionError ##它会在解释器检测发现超过最大递归深度时被引发
  44. +-- SyntaxError ##语法错误
  45. | +-- IndentationError ##缩进错误
  46. | +-- TabError ##Tab和空格混用
  47. +-- SystemError ##一般的解释器系统错误
  48. +-- TypeError ##对类型无效的操作
  49. +-- ValueError ##传入无效的参数
  50. | +-- UnicodeError ##当发生与 Unicode 相关的编码或解码错误时将被引发
  51. | +-- UnicodeDecodeError ##Unicode解码的时候的错误
  52. | +-- UnicodeEncodeError ##Unicode编码的时候的错误
  53. | +-- UnicodeTranslateError ##Unicode转换的时候的错误
  54. +-- Warning ##警告的基类
  55. +-- DeprecationWarning ##关于被弃用的特征的警告
  56. +-- PendingDeprecationWarning ##对于已过时并预计在未来弃用,但目前尚未弃用的特性相关警告的基类
  57. +-- RuntimeWarning ##可疑的运行时行为的警告
  58. +-- SyntaxWarning ##可疑的语法的警告
  59. +-- UserWarning ##用户代码生成警告
  60. +-- FutureWarning ##关于构造将来语义会有改变的警告
  61. +-- ImportWarning ##与在模块导入中可能的错误相关的警告的基类
  62. +-- UnicodeWarning ##与 Unicode 相关的警告的基类
  63. +-- BytesWarning ##与 bytes 和 bytearray 相关的警告的基类
  64. +-- ResourceWarning ##与资源使用相关的警告的基类

四、try 异常处理

4.1 try……expect语句

  1. try:
  2. <被检测的程序代码>
  3. expect <异常类型>:
  4. <异常处理的程序代码>

try语句中包含可能出现异常的代码。
except语句用来捕获异常的类中并执行异常处理。
ps:异常的名称也可以时空白的,表示此except语句处理所有类型的异常,即全捕获。异常的名称可以时一个也可以是多个。可以使用不同的expect语句处理不同的异常。
用户可以在expect语句内使用pass语句来忽略所发生的异常。

使用try……expect语句的工作原理:
1.如果try子句中被检测的程序代码有异常且被expect子句通过异常类型捕获到,则执行except子句中的异常处理程序代码
2.如果try子句中被检测到的程序代码没有发生异常,则不执行expect子句中的异常程序处理代码,程序继续向下执行
3.如果try子句中被检测到的程序代码有异常发生,但expect子句没有捕获到该异常,则程序会终止执行,并将该异常显示给最终用户。

  1. try:
  2. 12/0
  3. except ZeroDivisionError:
  4. print("数值不能除以0")
  5. ##结果
  6. 数值不能除以0
  7. try:
  8. 12/0
  9. except ZeroDivisionError:
  10. pass
  11. print("--------")
  12. ##结果
  13. --------

4.2 try……expect……else语句

当try语句没有检测到异常的时候,执行else子句的代码

  1. try:
  2. <被检测的程序代码>
  3. expect <异常类型>:
  4. <异常处理的程序代码>
  5. else
  6. <正常处理的程序代码>

如果try语句中的语句有错位u,如果错误类型与except语句捕获的错误类型不符,则不执行except子句中的代码,也不执行else子句中的代码,而是程序终止运行,并将异常显示给最终用户。

  1. a = [1,2,3,4,5,6]
  2. try:
  3. print(a[100])
  4. except IndexError:
  5. print("索引下标出界")
  6. else:
  7. print("程序无报错")
  8. ##结果
  9. 索引下标出界
  10. a = [1,2,3,4,5,6]
  11. try:
  12. print(a[0])
  13. except IndexError:
  14. print("索引下标出界")
  15. else:
  16. print("程序无报错")
  17. ##结果
  18. 1
  19. 程序无报错

4.3 处理多重异常的try……expect语句

使用带有多个expect子句的try语句结构,只要有某个expect语句捕获到了异常,则执行该expect子句下的程序代码,其他的expect子句不再进行异常的捕获。

  1. try:
  2. <被检测的程序代码>
  3. expect <异常类型>:
  4. <异常处理的程序代码>
  5. [expect <异常类型>:
  6. <异常处理的程序代码>]
  7. [expect <异常类型>:
  8. <异常处理的程序代码>]
  9. [else
  10. <正常处理的程序代码>]
  11. ##[]中的内容不是必须的

例子

  1. while True:
  2. try:
  3. x = eval(input("请输入第一个数据:"))
  4. y = int(input("请输入第二个数据:"))
  5. z = x/y
  6. except ValueError:
  7. print("应全部输入数值数据")
  8. except ZeroDivisionError:
  9. print("除数不能为零")
  10. except NameError:
  11. print("变量未定义")
  12. else:
  13. print("最终结果:",z)
  14. break
  15. ##结果
  16. 请输入第一个数据:15
  17. 请输入第二个数据:a
  18. 应全部输入数值数据
  19. 请输入第一个数据:15
  20. 请输入第二个数据:0
  21. 除数不能为零
  22. 请输入第一个数据:15
  23. 请输入第二个数据:3
  24. 最终结果: 5.0

4.4 try……expect……finally语句

无论try子句中的代码是否有异常产生,finally子句下面的程序代码都会被执行,可以用作清除异常使用。
finally必须时整个结构的最后一条语句,如果有else语句,则else语句必须出现在finally子句之前。

  1. try:
  2. <被检测的程序代码>
  3. expect <异常类型>:
  4. <异常处理的程序代码>
  5. finally:
  6. <必定执行的程序代码>

应用:
1.在通信过程中,无论通信是否发生错误,都需要在通信完成或者发生错误的时候关闭网络连接
2.在读一个文件的时候,无论是否有异常发生,最后都要关闭文件

  1. try:
  2. x = eval(input("请输入第一个数据:"))
  3. y = int(input("请输入第二个数据:"))
  4. z = x/y
  5. except ValueError:
  6. print("应全部输入数值数据")
  7. except ZeroDivisionError:
  8. print("除数不能为零")
  9. except NameError:
  10. print("变量未定义")
  11. else:
  12. print("最终结果:",z)
  13. finally:
  14. print('-----','end','-------')
  15. ##结果
  16. PS C:\Users\lh> & C:/Users/lh/AppData/Local/Programs/Python/Python37/python.exe e:/pythonstduy/iter.py
  17. 请输入第一个数据:15
  18. 请输入第二个数据:0
  19. 除数不能为零
  20. ----- end -------
  21. PS C:\Users\lh> & C:/Users/lh/AppData/Local/Programs/Python/Python37/python.exe e:/pythonstduy/iter.py
  22. 请输入第一个数据:15
  23. 请输入第二个数据:b
  24. 应全部输入数值数据
  25. ----- end -------
  26. PS C:\Users\lh> & C:/Users/lh/AppData/Local/Programs/Python/Python37/python.exe e:/pythonstduy/iter.py
  27. 请输入第一个数据:15
  28. 请输入第二个数据:5
  29. 最终结果: 3.0
  30. ----- end -------

五、抛出异常

当用户遇到已成的时候,用户可以通过抛出异常做相应地处理

5.1 raise语句

Python使用raise语句抛出一个指定的异常。
raise唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或异常的类(Exception的子类)

  1. raise NameError("这里使用raise抛出了一个异常")
  2. #结果
  3. Traceback (most recent call last):
  4. File "e:/pythonstduy/iter.py", line 173, in <module>
  5. raise NameError("这里使用raise抛出了一个异常")
  6. NameError: 这里使用raise抛出了一个异常

用户也可也直接输出异常的类名称

  1. raise IndexError()
  2. ##结果
  3. Traceback (most recent call last):
  4. File "e:/pythonstduy/iter.py", line 175, in <module>
  5. raise IndexError()
  6. IndexError
  1. class Fruit:
  2. def __init__(self,name):
  3. self.name =name
  4. def __getattr__(self,attr): ##增加新的属性
  5. if attr != 'name':
  6. raise AttributeError
  7. f= Fruit("苹果")
  8. print(f.name)
  9. f.prize()
  10. ##结果
  11. 苹果
  12. Traceback (most recent call last):
  13. File "e:/pythonstduy/iter.py", line 187, in <module>
  14. f.prize()
  15. File "e:/pythonstduy/iter.py", line 183, in __getattr__
  16. raise AttributeError
  17. AttributeError

5.2 结束解释器的运行

通过输入SystemExit异常强制结束Python解释器的运行。
QQ图片20201201152317.png
使用sys.exit()函数会输出一个SystemExit异常,sys.exit()函数会结束线程。

  1. import sys
  2. try:
  3. sys.exit()
  4. except SystemExit:
  5. print("目前还不能结束解释器的运行")
  6. ##结果
  7. 目前还不能结束解释器的运行

如果想正常结束Python解释器的运行,最好使用os模块的_exit()函数,里面必须有参数。
image.png

5.3 离开嵌套循环

在一个嵌套循环中,break语句只能离开最内层的循环,而不能离开嵌套循环,使用raise语句可以离开嵌套循环。

  1. class ExitLoop(Exception):
  2. pass
  3. try:
  4. i = 1
  5. while i<10:
  6. for j in range(1,10):
  7. print(i,j)
  8. if (i==2) and (j==2):
  9. raise(ExitLoop)
  10. i+=1
  11. except ExitLoop:
  12. print("当i=2且j=2的时候离开嵌套循环")
  13. ##结果
  14. 1 1
  15. 2 2
  16. i=2j=2的时候离开嵌套循环
  17. class ExitLoop(Exception):
  18. pass
  19. try:
  20. i = 1
  21. while i<10:
  22. for j in range(0,10):
  23. print(i,j)
  24. if (i==2) and (j==2):
  25. raise(ExitLoop)
  26. i+=1
  27. except ExitLoop:
  28. print("当i=2且j=2的时候离开嵌套循环")
  29. ##结果
  30. 1 0
  31. 2 1
  32. 3 2
  33. 4 3
  34. 5 4
  35. 6 5
  36. 7 6
  37. 8 7
  38. 9 8
  39. 10 9
  40. 不存在 i=2j=2的情况

六、自定义异常

用户可以自定义异常,与内置异常的区别是内置异常是定义在exceptions模块中的。当python解释器启动的时候,exceptions模块就会事先加载。
用户也可以自定义异常类,并且用户自定义的异常类必须从一个Python的内置异常类派生而来。
一般异常类在创建的时候都以“Error”结尾,与标准异常命名一样。

  1. class URLError(Exception):
  2. pass
  3. try:
  4. raise URLError("这是URL异常")
  5. except URLError as inst:
  6. print(inst.args[0])
  7. ##结果
  8. 这是URL异常
  9. #inst变量是用于自定义类URLError的实例变量,inst.args就是该用户定义异常类args属性值
  10. class MyError(Exception):
  11. def __init__(self,value):
  12. self.value =value
  13. def __str__(self):
  14. return repr(self,value)
  15. try:
  16. raise MyError(100)
  17. except MyError as e:
  18. print("发生异常的数值为:",e.value)
  19. ##结果
  20. 发生异常的数值为: 100

七、上下文管理语句

上下文管理语句with就可以实现语句块执行前的准备动作以及执行后的收尾动作。
with <上下文管理表达式> []:
<语句块>
<上下文管理表达式>是支持上下文管理协议的对象,eg:file、thread、LockType、threading.Lock,负责维护上下文环境
以变量的方式保存上下文管理对象。

  1. with open('hello.txt','w') as f:
  2. f.write('hello')
  3. f.writr('Python')
  4. 文件操作完成之后可以没有close()语句关闭文件,当程序完成的时候,文件会自动关闭。

八、程序调试

8.1 使用assert语句

assert <测试码> [,参数]
测试码是一段返回True或False的程序代码。如果测试码返回True,则继续运行后面的程序代码;如果测试码返回False,assert语句就会输出一个AssertionError异常,并输出assert语句的 [参数] 作为错误信息字符串。

  1. a= 100
  2. assert(a !=0),"Error ,a =0 "
  3. a= 0
  4. assert(a !=0),"Error ,a =0 "
  5. ##结果
  6. Traceback (most recent call last):
  7. File "e:/pythonstduy/iter.py", line 234, in <module>
  8. assert(a !=0),"Error ,a =0 "
  9. AssertionError: Error ,a =0
  10. try:
  11. x = int(input("x:"))
  12. y = int(input("y:"))
  13. s = "两次输入的数据不相等"
  14. assert x==y,s ##如果不相等的话,就会出现expect,抛出异常,
  15. except AssertionError:
  16. print(s)
  17. ##结果
  18. x:55
  19. y:66
  20. 两次输入的数据不相等
  21. PS C:\Users\lh> & C:/Users/lh/AppData/Local/Programs/Python/Python37/python.exe e:/pythonstduy/iter.py
  22. x:55
  23. y:55

8.2 debug内置变量

Python解释器有一个内置变量debugdebug在正常情况下的值为True。

  1. print(__debug__)
  2. ##结果
  3. True

当用户以最佳化模式启动Python解释器的时候,debug的值为False。

  1. PS C:\Users\lh> python -O
  2. Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
  3. Type "help", "copyright", "credits" or "license" for more information.
  4. >>> __debug__
  5. False

用户是不可以设置debug的值

  1. __debug__ = False
  2. ##结果
  3. __debug__ = False
  4. ^
  5. SyntaxError: assignment to keyword

debug也可以用来调试程序

  1. if __debug__:
  2. if not (<测试码>):
  3. raise AssertionError[,参数]

例子

  1. import types
  2. def checkType(arg):
  3. if __debug__:
  4. if not (type(arg)==str):
  5. raise AssertionError("参数的类型不是字符串")
  6. checkType(10)
  7. ##结果
  8. Traceback (most recent call last):
  9. File "e:/pythonstduy/iter.py", line 244, in <module>
  10. checkType(10)
  11. File "e:/pythonstduy/iter.py", line 243, in checkType
  12. raise AssertionError("参数的类型不是字符串")
  13. AssertionError: 参数的类型不是字符串