前言
我们在开发Python程序时经常会遇到一些错误(语法错误和异常),尤其是程序代码发生异常(Exceptions)时,如果不能及时捕获异常和有效处理异常,则程序运行会被终止,有可能会造成相应的后果;相反如果能及时捕获异常并有效处理异常,则能大大提高程序的健壮性。因此学会Python异常处理还是很有必要的。
本文会比较系统地介绍Python异常的相关知识。
本文分享内容的目录如下:
0. 前言
1. 了解Python错误
-1.1 语法错误
-1.2 异常
-1.3 Traceback信息
2. 了解内置异常类
-2.1 内置异常类层次结构
-2.2 异常基类
-2.3 具体异常类
-2.4 OS异常类
-2.5 警告异常类
3. 创建自定义异常类
4. 如何捕获和处理程序中的异常
-4.1 基本try-except语句块
-4.2 多重异常try-except语句块(基本情形1)
-4.3 多重异常try-except语句块(基本情形2)
-4.4 带嵌套的try-except语句块
-4.5 try-except-else语句块
-4.6 try-except-finally语句块
-4.7 try-except-else-finally语句块
5. 如何抛出一个异常
-5.1 如何抛出一个内置异常
-5.2 如何抛出一个自定义异常
6. 如何让程序输出更详细的异常信息
-6.1 面临问题-使用捕获的异常类只能获取较少的异常信息
-6.2 解决办法-使用traceback模块可以获取更详细的异常信息
7. 结束语
注:限于篇幅,本文只介绍第0章至第3章,剩下的第4章-第7章在《Python学习点滴04 - 学会异常处理(2)》中介绍。
本文开发环境为:
- Windows 7 64-bit
- Python 3.8.5 64-bit。
- IDLE (Python 3.8.5 64-bit)
1. Python错误
目前python提供两种可区分的错误:语法错误和异常。
1.1 语法错误 Syntax errors
一、语法错误描述:
语法错误(Syntax errors)又称解析错误(parsing errors),是在学习Python时最容易遇到的错误。
Python解析器(parser)在检测到代码语句存在语法错误时,程序根本就没执行,会在终端输出相关语法错误信息。
语法错误由于程序根本就没执行,所以并不会造成后果。
二、语法错误示例1:
在Python终端上输入代码语句时Python解析器输出语法错误信息的情形。
>>> def myfun() print('Hello Python') File "", line 1 def myfun() print('Hello Python') ^ SyntaxError: invalid syntax
二、语法错误示例2:
运行syntaxerror.py文件(文件内容为def myfun() print('Hello Python'))时会在终端输出语法错误信息的情形。
C:exception> python syntaxerror.py File "syntaxerror.py", line 1 def myfun() print('Hello Python') ^ SyntaxError: invalid syntax
三、语法错误说明:
上述语法错误示例1和语法错误示例2实际上一回事,只是分别代表两种发生情形:一种是在Python终端上输入代码语句时Python解析器输出语法错误信息;一种是在运行syntaxerror.py文件会在终端输出语法错误信息。
上述输出的示例语法错误信息说明如下:
1、输出第1行:给出了导致语法错误信息的文件名和行号,便于语法错误的定位及后续修复。
2、输出第2行:给出了Python解析器检测到的第一个存在语法错误的代码语句。
3、输出第3行:有一个方向朝上的小箭头字符,指向第2行中检测到语法错误的代码语句中的具体位置。上述示例中,检测到语法错误是在该代码语句中 print() 函数之前少了个冒号:。
4、输出第4行:给出语法错误信息:SyntaxError,具体是:invalid syntax
1.2 异常 Exceptions
一、异常描述:
即便Python程序中不存在语句错误,但在执行时,仍然可能会引发错误。
异常(Exceptions)是Python程序执行时检测到的错误,会在终端输出相应异常信息。
由于异常是程序执行时发生的,如果检测到异常但没有进行处理,或者处理不到位,那么程序就会终止执行,有可能会产生一些严重后果。因此一般而言,为了Python程序的健壮性而言,我们应该对程序中的异常进行捕获,然后给出有效的处理,防止程序执行终止。
二、异常示例1:
在Python终端上输入代码语句时Python解析器输出异常信息的情形。
>>> 1/0 Traceback (most recent call last): File "", line 1, in ZeroDivisionError: division by zero
二、异常示例2:
运行exception.py文件(文件内容为1/0)时会在终端输出异常信息的情形。
C:exception> python exception.py Traceback (most recent call last): File "c:/exception/exception.py", line 1, in 1/0 ZeroDivisionError: division by zero
三、异常说明:
上述异常示例1和异常示例2实际上一回事,只是分别代表两种发生情形:一种是在Python终端上输入代码语句时Python解析器输出异常信息;一种是在运行exception.py文件时会在终端输出异常信息。
上述输出的示例异常信息分三个部分:
1、异常信息标志行:见输出第1行。
见到Traceback (most recent call last):就知道下面是具体的异常信息。
2、异常信息定位部分:见输出第1行与输出最后一行中间的几行。
2-1)、输出第2行给出了导致异常信息的文件名和行号,便于异常的定位及后续修复。
2-2)、输出第3行给出了Python解析器检测到的发生异常的代码语句/表达式。
3、异常信息类型内容部分:见输出最后一行。
给出异常信息的类型和内容。本示例异常类型为:ZeroDivisionError,异常内容是:division by zero(即被0除)。
1.3 Traceback信息
一、Traceback信息描述:
Traceback信息是异常堆栈信息(亦简称异常信息),当Python程序执行过程中发生异常时,程序就会抛出一个异常信息,如果程序没有指定相应的异常处理方法或异常处理方法不到位,Python就会使用Traceback来输出发生异常时代码执行栈的情况。
通过Traceback信息,开发者可以更好地对出现的异常进行定位和分析。
Traceback信息跟本文第1.2章节中异常信息是一回事,本节再介绍一个复杂些的示例。
二、Traceback信息示例:
1、示例代码(traceback_test.py)
def divfun(num1, num2): return num1/num2 def main(): a = 10 b = 0 result = divfun(a, b) print(result) if __name__ == '__main__': main()
2、执行traceback_test.py文件时会在终端输出Traceback信息的情形。
C:exception> python traceback_test.py Traceback (most recent call last): File "c:/exception/traceback_test.py", line 11, in main() File "c:/exception/traceback_test.py", line 7, in main result = divfun(a, b) File "c:/exception/traceback_test.py", line 2, in divfun return num1/num2 ZeroDivisionError: division by zero
三、Traceback信息说明:
上述输出的示例的Traceback信息分三个部分:
1、异常信息标志行:见输出第1行。
见到Traceback (most recent call last):就知道下面是具体的异常信息。
2、异常信息定位部分:见输出第1行与输出最后一行中间的几行(输出第2行至第7行)。
2-1)、输出第2行和第3行给出了导致异常信息的文件名中代码第11行的main()语句。
2-2)、输出第4行和第5行给出了导致异常信息的文件名中代码第7行的result = divfun(a, b)语句。
2-3)、输出第6行和第7行给出了导致异常信息的文件名中代码第2行的return num1/num2语句。
通过上面逐层跟踪调用的方法,直至定位到本示例中真正导致异常信息的位置是位于文件的第2行(divfun()函数中的return num1/num2语句),即输出第6行和第7行的提示信息。
3、异常信息类型内容部分:见输出最后一行。
给出异常信息的类型和内容。本示例异常类型为:ZeroDivisionError,异常内容是:division by zero(即被0除)。
2. 了解内置异常类
2.1 内置异常类层次结构
Python内置异常的类层级结构如下:
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError | +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError | +-- UnboundLocalError +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning
从上面类层次结构图中可以看出在Python中异常类命名的主要后缀有Error、Warning、Exception、Exit、Iteration和Interrupt。
2.2 异常基类
下列异常主要被用作其他异常的基类。
2.3 具体异常
以下异常属于经常被引发的异常。
2.3.1 AssertionError
一、描述:当 assert 语句失败时将被引发(即当assert后面的条件为假时,程序将终止并抛出一个AssertionError异常)。
二、示例:
>>> assert '北京' > '上海' # 当assert后的条件为假时,程序终止并抛出一个AssertionError异常 >>> assert '北京' < '上海' Traceback (most recent call last): File "", line 1, in assert '北京' < '上海' AssertionError
2.3.2 AttributeError
一、描述:当试图访问的对象属性不存在时将被引发,会抛出AttributeError异常。
二、示例:
>>> a = 2 >>> a.add Traceback (most recent call last): File "", line 1, in a.add AttributeError: 'int' object has no attribute 'add'
2.3.3 ImportError
一、描述:当 import 语句尝试加载模块遇到麻烦时将被引发,会抛出ImportError异常。
二、示例:
>>> from math import abcd Traceback (most recent call last): File "", line 1, in from math import abcd ImportError: cannot import name 'abcd' from 'math' (unknown location)
2.3.4 IndexError
一、描述: 当序列抽取超出范围时将被引发。当在使用序列时,如果索引超出序列范围,则将被引发,会抛出IndexError异常。
二、示例:
>>> a = [1, 2, 3] >>> a[4] Traceback (most recent call last): File "", line 1, in a[4] IndexError: list index out of range
2.3.5 KeyError
一、描述: 当在现有字典(键集合)中找不到指定的关键字(Key值)时将被引发,会抛出KeyError异常。
二、示例:
>>> a = {'010':'北京', '021':'上海'} >>> a['010'] '北京' >>> a['022'] Traceback (most recent call last): File "", line 1, in a['022'] KeyError: '022'
2.3.6 NameError
一、描述: 当某个局部或全局名称未找到时将被引发,会抛出NameError异常。此异常仅用于非限定名称。
二、示例:
>>> abcd Traceback (most recent call last): File "", line 1, in abcd NameError: name 'abcd' is not defined
2.3.7 SyntaxError
一、描述: 当解析器遇到语法错误时将被引发,会抛出SyntaxError异常。
二、示例:
>>> print abcd SyntaxError: Missing parentheses in call to 'print'. Did you mean print(abcd)?
2.3.8 TypeError
一、描述: 当一个操作或函数被应用于类型不适当的对象时将被引发,会抛出TypeError异常。
二、示例:
>>> 1 + 'a' Traceback (most recent call last): File "", line 1, in 1 + 'a' TypeError: unsupported operand type(s) for +: 'int' and 'str'
2.3.9 ValueError
一、描述: 当操作或函数接收到具有正确类型但值不适合的参数,并且情况不能用更精确的异常(例如 IndexError) 来描述时将被引发,会抛出ValueError异常。
二、示例:
>>> i = int(input('请输入一个整数:')) 请输入一个整数:a Traceback (most recent call last): File "", line 1, in i = int(input('请输入一个整数:')) ValueError: invalid literal for int() with base 10: 'a'
2.3.10 ZeroDivisionError
一、描述: 当除法或取余运算的第二个参数为零时将被引发,会抛出ZeroDivisionError异常。
二、示例:
>>> 1/0 Traceback (most recent call last): File "", line 1, in 1/0 ZeroDivisionError: division by zero
2.4 OS异常类
下列异常均为 OSError 的子类,它们将根据系统错误代码被引发。
2.5 警告异常类
下列异常被用作警告类别。
3. 自定义异常类
开发者可以在Python中自定义异常类。在Python中,所有异常必须为一个派生自 BaseException 类或其子类的实例。自定义异常类通常也需要继承 Exception 类或其子类。
下面示例自定义一个继承自 Exception 类的自定义异常类MyException:
# 自定义异常类MyExceptionclass MyException(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value)
当Python程序(custom_test.py)抛出的该自定义异常,如果不对该自定义异常进行有效处理,就会在终端显示Traceback信息,示例如下:
Traceback (most recent call last): File "c:/exception/custom_test.py", line 11, in raise MyException('自定义异常') MyException: 自定义异常
上述输出的示例异常信息(Traceback信息)分三个部分:
1、异常信息标志行:见输出第1行。内容为Traceback (most recent call last):。
2、异常信息定位部分:见输出第1行与输出最后一行中间的几行(输出第2行至第3行)。
2-1)、输出第2行给出了导致异常信息定位于:文件名中代码第11行。
2-2)、输出第3行给出了导致异常信息定位于:raise MyException('自定义异常')语句。
3、异常信息类型内容部分:见输出最后一行。
给出异常信息的类型和内容。本示例异常类型为:MyException,异常内容是:自定义异常。
4. 如何捕获和处理程序中的异常
本章介绍如何捕获和处理程序中的异常的多种组合(基本try-except语句块、两种情形的多重异常try-except语句块、带嵌套的try-except语句块、try-except-else语句块、try-except-finally语句块和try-except-else-finally语句块)。
详见《Python学习点滴04 - 学会异常处理(2)》第4章中介绍。
5. 如何抛出一个异常
本章介绍如何抛出一个内置异常、自定义异常。
详见《Python学习点滴04 - 学会异常处理(2)》第5章中介绍。
6. 如何让程序输出更详细的异常信息
本章介绍如何让程序输出更详细的异常信息(面临问题 - 使用捕获的异常类只能获取较少的异常信息、解决办法 - 使用traceback模块可以获取更详细的异常信息)。
详见《Python学习点滴04 - 学会异常处理(2)》第6章中介绍。
结束语
见《Python学习点滴04 - 学会异常处理(2)》最后一章中介绍。