一、异常处理机制
和 其他编程语言一样,Python 也提供了处理异常的机制。
Python 异常处理机制会涉及 try、except、else、finally 这 4 个关键字和 raise 语句 。
1、错误和异常
Python 编写程序时遇到的异常可大致分为 2 类:语法错误和运行时异常。
(1)错误
语法错误:也叫做解析错误,就是解析代码时出现的错误。
当代码不符合 Python 语法规则时,Python解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早探测到错误的语句,并以调用栈的形式显示出来。
示例代码如下:
print('Hello world)
# 错误信息:
File "D:\JQWS\PythonWS\demo1\dir5\demo1.py", line 3
print('Hello world)
^
SyntaxError: unterminated string literal (detected at line 3)
(2)运行时异常
运行时异常:即程序在语法上都是正确的,但在运行时发生了错误。把在运行期检测到的错误被称为异常(Exceptions)。
示例代码如下:
a = 1 / 0
print(a)
# 错误信息:
Traceback (most recent call last):
File "D:\JQWS\PythonWS\demo1\dir5\demo1.py", line 5, in <module>
a = 1/0
~^~
ZeroDivisionError: division by zero
常见的运行时异常如下:
- NameError:尝试访问一个未声明的变量时,引发此异常
- IndexError :索引超出序列范围会引发此异常
- KeyError:字典中查找一个不存在的关键字时引发此异常
- TypeError:不同类型数据之间的无效操作
- ZeroDivisionError:除法运算中除数为 0 引发此异常
- AttributeError:当试图访问的对象属性不存在时抛出的异常
2、异常处理
开发者可以使用异常处理全面地控制自己的程序。异常处理不仅仅能够管理正常的流程运行,还能够在程序出错时对程序进行必的处理。大大提高了程序的健壮性和人机交互的友好性。
2.1 try/except
使用 try except语句捕获并处理异常,其基本语法格式如下:
try:
可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
处理异常的代码块2
except [Exception]:
处理其它异常
- 一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常。
- 一个except子句可以同时处理一个或者多个异常,这些异常将被放在一个括号里成为一个元组。
如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。Python 解释器会寻找能处理该异常对象的 except 块,如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。
如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。
示例代码如下:
try:
a = int(input("输入被除数:"))
b = int(input("输入除数:"))
c = a / b
print("您输入的两个数相除的结果是:", c)
except (ValueError, ArithmeticError):
print("程序发生了数字格式异常、算术异常之一")
except ZeroDivisionError:
print("除数不能为0")
except Exception as e:
# 访问异常的错误编号和详细信息
print(e.args)
print(str(e))
print(repr(e))
print("程序继续向下运行")
2.2 try/except…else
try/except 语句还有一个可选的 else 子句,在except 子句之后添加一个 else 子句,即try except else结构。
其基本语法格式如下:
try:
可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
处理异常的代码块2
except [Exception]:
处理其它异常
else:
try没有发生任何异常的时,才会执行的语句
else 子句含义:
只有在 try 子句没有发生任何异常的时候执行 else 块中的代码。否则不执行它。else 子句必须放在所有的 except 子句之后。
示例代码如下:
try:
a = int(input("输入被除数:"))
b = int(input("输入除数:"))
c = a / b
print("您输入的两个数相除的结果是:", c)
except (ValueError, ArithmeticError):
print("程序发生了数字格式异常、算术异常之一")
except ZeroDivisionError:
print("除数不能为0")
except Exception as e:
# 访问异常的错误编号和详细信息
print(e.args)
print(str(e))
print(repr(e))
else:
print('没有出现任何异常')
print("程序继续向下运行")
2.3 try-finally
try-finally 语句基本语法格式如下:
try:
可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
处理异常的代码块2
except [Exception]:
处理其它异常
else:
try没有发生任何异常的时,才会执行的语句
finally:
无论 try 块是否发生异常都会执行的语句
在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。
注意:
和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。
示例代码如下:
try:
a = int(input("请输入 a 的值:"))
print(20/a)
except:
print("发生异常!")
else:
print("执行 else 块中的代码")
finally :
print("执行 finally 块中的代码")
2.4 抛出异常
Python 使用 raise 语句抛出一个指定的异常。
raise语法格式如下:
raise [exceptionName [(reason)]]
也就是说,raise 语句有如下三种常用的用法:
- raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
- raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
- raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
示例代码如下:
try:
a = input("输入被除数:")
# 判断用户输入的是否为数字
if (not a.isdigit()):
# raise
# raise ValueError()
raise ValueError("a 必须是数字")
b = int(input("输入除数:"))
c = a / b
print("您输入的两个数相除的结果是:", c)
except ValueError as e:
print("引发异常:", repr(e))
except [RuntimeError, TypeError]:
raise
except Exception as e:
# 访问异常的错误编号和详细信息
print(e.args)
print(str(e))
print(repr(e))
except:
print("未知异常")
3、获取异常详情
捕获异常时,有 2 种方式可获得更多的异常信息,分别是:
- 使用 sys 模块中的 exc_info 方法;
- 使用 traceback 模块中的相关函数。
3.1 使用 sys 模块
exc_info() 方法会将当前的异常信息以元组的形式返回。
该元组中包含 3 个元素,分别是:
- type:异常类型的名称,它是 BaseException 的子类。
- value:捕获到的异常实例。
- traceback:是一个 traceback 对象。
示例代码如下:
# 引入 sys 模块
import sys
try:
x = int(input("请输入一个被除数:"))
print("30除以",x,"等于",30/x)
except:
print(sys.exc_info())
print("其他异常...")
我们可以使用 traceback 模块的方法,查看结果中第三元素包含的内容(raceback 对象)。
调用 traceback 模块中的 print_tb 方法,并将 sys.exc_info() 输出的 traceback 对象作为参数参入。
示例代码如下:
# 引入 sys 模块
import sys
# 引入 traceback模块
import traceback
try:
x = int(input("请输入一个被除数:"))
print("30除以", x, "等于", 30 / x)
except:
# print(sys.exc_info())
traceback.print_tb(sys.exc_info()[2])
print("其他异常...")
3.2 traceback 模块
使用 traceback 模块,该模块可以用来查看异常的传播轨迹,追踪异常触发的源头。
traceback中的函数有很多,上面使用了 traceback.print_tb()函数,这里再使用一个 traceback.print_exc()函数。
traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中。
print_exc() 函数的完整形式是:
print_exception(etype, value, tb[,limit[, file]])
参数说明:
- etype:指定异常类型;
- value:指定异常值;
- tb:指定异常的traceback 信息;
- limit:用于限制显示异常传播的层数。如果不设置 limit 参数,则默认全部显示。
- file:指定将异常传播轨迹信息输出到指定文件中。如果不指定该参数,则默认输出到控制台。
我们可以使用 except 块捕获异常,并在其中打印异常传播信息,包括把它输出到文件中。例如如下程序:
# 导入 trackback模块
import traceback
class SelfException(Exception):
pass
def main():
firstMethod()
def firstMethod():
secondMethod()
def secondMethod():
thirdMethod()
def thirdMethod():
raise SelfException("自定义异常信息")
try:
main()
except:
# 捕捉异常,并将异常传播信息输出控制台
traceback.print_exc()
# 捕捉异常,并将异常传播信息输出指定文件中
traceback.print_exc(file=open('log.txt', 'a'))
三、自定义异常类
用户自定义异常:创建一个新的异常类。该类继承 Exception 类,可以直接继承,或者间接继承。
大多数的异常的名字都以"Error"结尾,我们自定义异常类的命名推荐也使用它结尾。
示例代码如下:
# 自定义异常类
class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
try:
# 测试:抛出异常
raise MyError(2 * 2)
except MyError as e:
print('自定义异常:', e.value)
当创建一个模块有可能抛出多种不同的异常时,通常的做法是为这个包建立一个基础异常类
,然后基于这个基础类为不同的错误情况创建不同的子类。
四、assert(断言)
Python assert 语句,又称断言语句,它用于判断一个表达式,在表达式条件为 false 的时候触发异常。
该语句的语法结构为:
assert 表达式
- 如果值为真,则程序可以继续往下执行;反之,Python 解释器会触发异常。
assert 语句的执行流程可以用 if 判断语句来表示,代码如下:
if 表达式==True:
程序继续执行
else:
程序报 AssertionError 错误
示例代码如下:
x = int(input("请输入一个数:"))
# 断言:数是否位于正常范围内
assert 0 <= x <= 100
# 只有当 x 位于 [0,100]范围内,程序才会继续执行,否则会报错:AssertionError
print("x=", x)
– 求知若饥,虚心若愚。