错误的分类
编写程序过程中遇到的错误都分为两类:语法错误与运行时错误。
语法错误:当代码不符合Python语法规则时, 在解析过程中会报SyntaxError。
运行时错误:即语句或表达式在语法上都是正确的, 但在运行时发生了错误。
当程序发生异常时,默认会终止程序的。可以通过使用捕获异常的方式获取异常名称,并通过代码逻辑让程序继续执行,这种逻辑叫做异常处理。
异常的基本语法
异常语法的定义:
try:
〈语句〉 #运行别的代码
except <名字〉:
〈语句〉
except <名字〉,〈数据〉:
〈语句〉 #如果引发了’name’异常, 获得附加的数据
else:
〈语句〉 #如采没有异常发生, 则执行该分支语句
except关键字还可以同时接收多个异常具体的写法是在except后面加个括号, 将要接收的异常当作参数传入。
try:
x = int(input('请入一个被除数:')) #等待输入一个数, 并赋位给x
print('30除以', x, '等于', 30/x) #输出30以x
except(ZeroDivisionError,ValueError): #同时捕获ZeroDivisionError与ValueError异常
print('输入错误, 重新输入……')
except: #捕获其他异常
print('其他异常……')
try……except...…语句后面还可以跟else语句。当没有异常发生时, 将执行else语句。else语句是个可选语旬, 必须要放在所有except语句后面。
捕获异常类型:通过except后面跟着Exception as e的语旬, 可得到异常类型e。
输出异常详细信息
捕获异常时, 可以使用sys模块中的exc_info函数, 或使用traceback模块中的相关函数, 来获得更多的异常信息。详细介绍如下:
1、 sys的exc_info函数
模块sys中有两个函数可以返回异常的全部信息:一个是exc_info;另一个是last_traceback。两个函数有相同的用法及功能。
exc_info函数会将当前的异常信息以元组的类型返回。元组内包含3个元素, 分别为type、value和traceback。
Type:异常类型的名称, 它是BaseException的子类
value:捕获到的异常实例
traceback:是一个traceback对象
import sys
try:
x = int(input('请输入一个被除数:'))
print('30除以', x, '等于', 30/x)
except:
print(sys.exc_info())
#(<class 'ZeroDivisionError' >, ZeroDivisionError ('division by zero ',) , <traceback
#object at Ox000000000C745748 >)
print('其他异常……')
输出结果的第2行为异常的全部信息。该信息是一个元组类型。元组的第1个元素是一个ZeroDivisionError类:第2个元素是异常类型ZeroDivisionError类的一个实例;第3个元素为一个traceback对象。
2、 traceback对象的显示
要查看traceback对象的内容, 需要先引入traceback模块, 调用traceback模块中的print_tb方法, 并将sys.exc_info输出的traceback对象传入。print_tb方法专用于显示traceback对象的内容。
import traceback
import sys
try:
x = int(input('请输入一个被除数:'))
print('30除以', x, '等于', 30/x)
except:
traceback.print_tb(sys.exc_info()[2]) #打印traceback对象
print('其他异常……')
else:
print("再见")
3、 traceback模块的其它函数
通过traceback模块的载入, 可以更简单地获得更多异常信息显示。比如调用traceback对象的print_exc方法, 可以直接将异常内容打印出来。
在traceback模块中, 还有功能类似的print_exception函数。但是print_exception要传入sys.exc_info()的结果。
# 下面两行代码等价
traceback.print_exc()
traceback.print_exception(*sys.exc_info())
捕获预处理异常
try语句在执行时, 如果出现了一个异常, 该语句的剩余部分将被跳过;如果该异常的类型匹配到了except后面的异常名, 则该except后的语句将被执行。
注意:如果except后面没有跟异常名, 必须放在所有捕获异常的语句之后, 表示它可以匹配任何类型的异常。
try语句的工作原理:
(1)当执行一个try语句后, Python就在当前程序的上下文中做标记。
(2)如果程序出现异常, 系统就会回到标记处。接着执行第一个匹配该异常的except子句。异常处理完毕, 控制流就跳过整个try语句(除非在处理异常时又引发新的异常)。
(3)如果程序出现异常, 但没有找到相匹配的except子句。异常将被递交到上层的try或者程序的最上层(这样将结束程序, 并打印默认的出错信息)。
(4)如果try子句在执行时没有发生异常, Python将执行else的语句(如果有else的话), 然后控制流跳过整个try语句。
常见异常
创建异常
创建异常又叫抛出异常, 也叫作触发异常, 是主动向系统报出异常, 使用关键宇raise来实现。
语法:raise [ Exception [ , args [ , traceback ] ] ]
Exception:异常参数值, 指代常的类型(例如, NameError)。该参数是可选的, 默认是None。
traceback:是可选的(在实践中很少使用), 代表所要跟踪的异常对象。
注意:raise抛出的异常必须是一个异常实例或类(派生自Exception的类)。
try:
x = int(input('请输入一个被除数:'))
if 0 == x:
raise ValueError('输入错误:不能做被除数')
print('30除以', x, '等于', 30/x)
except Exception as e:
print(e)
except ZeroDivisionError:
print('被除数不等于0, 重新输入......')
except
print('其他异常……')
异常的最终处理
Python中, finally语句是与町和except语句配合使用的。
finally语句中的内容般都是用来做清理工作的。无论try中的语句是否跳入except中, 最终都要进入finally语句, 并执行finally语句的分支代码。
finally与else的区别:
else语句只在没有异常发生的情况下执行。
finally语句则不管异常发生与否都会执行。
finally语句总是在退出try语句前被执行, 无论是正常退出、异常退出, 还是通过break、continue、return语句退出。
断言
断言,使用assert关键宇后面接着一个条件表达式。如果条件表达式为真, 意味着程序当前的条件与开发人员自己断言的情况一致, 则程序继续行;如果为假, 则表明一定是前面发生了错误, 程序停止运行, 报出异常。
Python中, 如果断言后面的条件语句失败了, 还可以为其指定对应的字符串输出。具体做法是:直接在assert后面的条件语句之后, 加上“字符串”
assert 1 != 1,("1不等于1, 报错") #断言1不等于1
自定义异常
通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承
>>> 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('My exception occurred, value:', e.value)
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'