软件程序在运行过程中,非常可能出现异常,比如:程序在运行中,突然内存或硬盘满了;为了增加程序的健壮性,在遇到意外情况(出现异常)时让程序做出合理的处理,在编写程序时需要考虑如何处理异常情况。
异常机制本质:当程序出现异常,程序安全的退出,处理完后继续执行的机制。
python中一切都是对象,异常也采用对象的方式来处理。处理过程:
1、抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给解释器。
2、捕获异常:解释器得到该异常后,寻找相应的代码来处理该异常。
异常的示例
下面代码首先从控制台读取字符串,并将字符串转化为 int 数据类型,接着打印输入的数字,并将打印5除以该数字。当输入数字 0 程序会发生错误 ZeroDivisionError: division by zero ,输入字符串时程序会发生错误 ValueError 。
示例代码如下
i = int(input("请输入数字:"))
print(i)
print(5/i)
代码运行结果
示例代码如下(该程序只有当输入数字 66 时程序才会退出,否则将一直执行,且当输入的不是数字时会打印异常信息)
while True:
try:
x = int(input("请输入一个数字(输入66时程序退出):"))
print("输入的数字是:",x)
if x == 66:
print("程序退出")
break
except Exception as e:
print("异常,输入的不是数字!")
print(e)
代码运行结果
请输入一个数字(输入66时程序退出):88
输入的数字是: 88
请输入一个数字(输入66时程序退出):CSDN
异常,输入的不是数字!
invalid literal for int() with base 10: 'CSDN'
请输入一个数字(输入66时程序退出):
异常,输入的不是数字!
invalid literal for int() with base 10: ''
请输入一个数字(输入66时程序退出):66
输入的数字是: 66
程序退出
异常类继承层次
BaseException # 所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规异常的基类
+-- StopIteration # 迭代器没有更多的值
+-- StandardError # 标准错误
| +-- BufferError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| | +-- VMSError (VMS)
| +-- EOFError
| +-- ImportError
| +-- LookupError
| | +-- IndexError
| | +-- KeyError
| +-- MemoryError
| +-- NameError
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError
| | +-- NotImplementedError
| +-- SyntaxError
| | +-- IndentationError
| | +-- TabError
| +-- SystemError
| +-- TypeError
| +-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarnin
+-- ImportWarnin
+-- UnicodeWarnin
+-- BytesWarning
从异常类的继承层次可见,异常根类是 BaseException ,它的子类很多,其中 Exception 是非系统退出的异常,他包含了很多常用异常。如果自定义异常需要继承 Exception 及其子类,不要直接继承 BaseException 。此外,还有一类异常是 Warning ,他表示“警告”,提示程序潜在问题。
常见异常
AttributeError异常
该异常表示试图访问一个类中不存在的成员(包括:成员变量、属性和成员方法)而引发的异常。
示例代码如下
class Animal:
pass
a = Animal()
print(a.run())
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 4, in <module>
print(a.run())
^^^^^
AttributeError: 'Animal' object has no attribute 'run'
OSError异常
OSError 是操作系统相关异常。Python3.3版本后 IOError (输入输出异常)也并入OSError 异常,所以输入输出异常也属于 OSError 异常。例如:“未找到文件”或“磁盘已满”异常。
示例代码如下
f = open("OSError.txt")
# 当前目录下不存在该文件,会抛出FileNotFoundErrory异常
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 1, in <module>
f = open("OSError.txt")
^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'OSError.txt'
IndexError异常
IndexError 异常是访问序列元素时,下标索引超出取值范围所引起的异常。
示例代码如下
a = ["邂","逅","自","己"]
print(a[4])
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 2, in <module>
print(a[4])
~^^^
IndexError: list index out of range
KeyError异常
该异常是由于试图访问字典里不存在的键而引发的异常。
示例代码如下
a = {"name":"邂逅自己","age":18,"school":"primary"}
print(a["name"]) # 输出 邂逅自己
print(a[100]) #没有该键
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 3, in <module>
print(a[100]) #没有该键
~^^^^^
KeyError: 100
邂逅自己
NameError异常
该异常是试图使用一个不存在的变量而引发的异常。
输入下面代码
a = {"name":"邂逅自己","age":18,"school":"primary"}
print(a[name])
代码运行如下
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 2, in <module>
print(a[name])
^^^^
NameError: name 'name' is not defined
注意:如果之前没有创建过变量 a ,使用 a = 10 代码则不会引发异常,因为赋值时,如果变量不存在就会创建它,所以不会引发异常。
TypeError异常
该异常是试图传入与所需数据类型不同的变量引起的。
示例代码如下
i = '6' #i为str类型,下面需要的是整数类型
print(5/i)
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 2, in <module>
print(5/i)
~^~
TypeError: unsupported operand type(s) for /: 'int' and 'str'
ValueError异常
该异常是由传入一个无效的参数值而引发的异常。
示例代码如下
i = 'CSDN'
print(5/int(i))
代码运行结果
Traceback (most recent call last):
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 2, in <module>
print(5/int(i))
^^^^^^
ValueError: invalid literal for int() with base 10: 'CSDN'
SyntaxError异常
该异常是由语法错误引起的
示例代码如下
int a = 3
print(a)
代码运行结果
File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 1
int a = 3
^
SyntaxError: invalid syntax
Process finished with exit code 1
常见异常汇总
异常名称 | 说明 |
---|---|
ArithmeticError | 所有数值计算错误的基类 |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
BaseException | 所有异常的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
EnvironmentError | 操作系统错误的基类 |
EOFError | 没有内建输入,到达EOF标记 |
Exception | 常规错误的基类 |
FloatingPointError | 浮点计算错误 |
FutureWarning | 关于构造将来语义会有改变的警告 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
ImportError | 导入模块/对象失败 |
IndentationError | 缩进错误 |
IndexError | 序列中没有此索引(index) |
IOError | 输入/输出操作失败 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
KeyError | 映射中没有这个键 |
LookupError | 无效数据查询的基类 |
MemoryError | 内存溢出错误(对于Python解释器不是致命的) |
NameError | 未声明/初始化对象(没有属性) |
NotImplementedError | 尚未实现的方法 |
OSError | 操作系统错误 |
OverflowError | 数值运算超出最大限制 |
PendingDeprecationWarning | 关于特性将会被弃用的警告 |
ReferenceError | 弱引用(Weak referencce)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
StandardError | 所有的内建标准异常的基类 |
StopIteration | 迭代器没有更多的值 |
SyntaxError | Python语法错误 |
SyntaxWarning | 可疑的语法的警告 |
SystemError | 一般的解释器系统错误 |
SystemExit | 解释器请求退出 |
TabError | Tab和空格混用 |
TypeError | 对类型无效的操作 |
UnboundLocalError | 访问未初始化的本地变量 |
UnicodeDecodeError | Unicode解码时的错误 |
UnicodeEncodeError | Unicode编码时错误 |
UnicodeError | Unicode相关的错误 |
UnicodeTranslateError | Unicode转换时错误警告 |
UserWarning | 用户代码生成的警告 |
ValueError | 传入无效的参数 |
Warning | 警告的基类 |
WindowsError | 系统调用失败 |
ZeroDivisionError | 除(或取模)零(所有数据类型) |
捕获异常
try-except语句
当出现异常时,若当前函数有能力解决,则捕获异常进行处理;若没有能力解决,则抛给上层调用者(函数)处理。如果上层调用者仍然无法处理,则继续抛它的上层调用者;直到有能力处理它。若所有函数都没有处理该异常,那么Python解释器会终止程序运行。
基本格式:
try:
被监控可能引发异常的语句块
except Exception [as e]:
异常处理语句块
- try 块包含着可能引发异常的代码,except用来捕捉和处理发生的异常
- 执行时若 try 块中没有引发异常,则会跳过 except 继续执行后面的代码
- 执行的时候,如果 try 块中发生了异常,则跳过 try 块中的后续代码,跳到相应的 except 块中处理异常;异常处理完后,继续执行后面的代码
输入下面代码
import datetime as dt # 导入Python内置的datetime日期时间模块,并将其命名为dt
def read_date(in_date): # 定义函数,将传入的字符串转换为日期,并进行格式化
try:
date = dt.datetime.strptime(in_date,'%Y-%m-%d')
return date
except ValueError as e: # 捕获ValueError异常
print('发生了 ValueError 异常')
print(e) # 获取异常对象
str_date = '2020-B-18'# 此处为无效日期,有效日期如 2020-8-18
print('日期 = {0}'.format(read_date(str_date)))
代码运行结果
发生了 ValueError 异常
time data '2020-B-18' does not match format '%Y-%m-%d'
日期 = None
多个 except 代码块
如果 try 代码块中有很多语句抛出异常,而且抛出异常的种类很多,那么可以在 try 后面跟多个except代码块。其语法格式如下:
try:
<可能会抛出异常的语句>
except[异常类型1]:
<处理异常>
except[异常类型2]:
<处理异常>
...
except[异常类型n]:
<处理异常>
注意:当捕获多个异常类之间存在父子关系时,捕获异常顺序与 except 代码块的顺序有关。从上到下先捕获子类,后捕获父类,否则子类捕获不到。
示例代码如下
import datetime as dt
def read_date_file(filename):
try:
file = open(filename) # open函数从文件中读取字符串
in_date = file.read()
in_date = in_date.strip() # 剔除字符串前后空白字符(包括空格、制表符、换行和回车等字符)
date = dt.datetime.strptime(in_date,'%Y-%m-%d')
return date
except ValueError as e:
print(e)
except FileNotFoundError as e:
print(e)
except OSError as e:
print(e)
date = read_date_file('file.txt')
print('日期 = {0}'.format(date))
代码运行结果
[Errno 2] No such file or directory: 'file.txt'
日期 = None
上面代码需要注意 FileNotFoundError 与 OSError 不能调换位置,否则 except FileNotFoundError as e 代码块永远不会进入。
try-except语句嵌套
Python中 try-except 语句可以任意嵌套,不仅可以嵌套在 try 语句中,也可以嵌套在 except 代码块或 finally 代码块。try-except 代码块会使程序流程变得复杂,如果能用多 except 捕获的异常,尽量不要使用 try-except 嵌套。
示例代码如下(代码中通过捕获 ValueError 异常的 try-catch 语句嵌套在 FileNotFoundError 和 OSError 异常的 try-catch 语句中)
import datetime as dt
def read_date_file(filename):
try:
file = open(filename)
try:
in_date = file.read()
in_date = in_date.strip() # 剔除字符串前后空白字符(包括空格、制表符、换行和回车等字符)
date = dt.datetime.strptime(in_date,'%Y-%m-%d')
return date
except ValueError as e:
print(e)
except FileNotFoundError as e:
print(e)
except OSError as e:
print(e)
date = read_date_file('file.txt')
print('日期 = {0}'.format(date))
多重异常捕获
对于多个不同类型的异常,要求捕获之后的处理都是调用同一方法时,可以把这些异常都放到一个元组中,这样可以大大简化代码。
示例代码如下
import datetime as dt
def read_date_file(filename):
try:
file = open(filename) # open函数从文件中读取字符串
in_date = file.read()
in_date = in_date.strip() # 剔除字符串前后空白字符(包括空格、制表符、换行和回车等字符)
date = dt.datetime.strptime(in_date,'%Y-%m-%d')
return date
except (ValueError,OSError) as e: # 多重异常捕获
print(e)
date = read_date_file('file.txt')
print('日期 = {0}'.format(date))