目录:
异常处理
一、介绍
1、什么是异常?
异常是程序发生错误的信号,程序一旦出现错误,便会产生一个异常,若程序中没有处理它,就会抛出异常,程序的运行也随之终止。
2、在python中,错误出发的异常分为两种
1、语法错误: SyntaxError ,这种错误应该在程序运行前就修改正确
2、逻辑错误: TypeError/NameError
二、异常处理
为了保证程序的容错性与可靠性,即正赛遇到错误时有相应的处理机制不会人有程序崩溃掉,我们需要对异常进行处理,处理的基本形式为:
try:
被检测的代码块
except 异常类型:
检测到异常,就执行这个位置的逻辑
# 举例:
try:
print('start...')
print(x) # 引用了一个不存在的名字,触发异常NameError
print('end...')
except NameError as e: # as语法将异常类型的值赋值给变量e,这样我们通过打印e便可以知道错误的原因
print('异常值为:%s' %e)
print('run other code...')
#执行结果为
start...
异常值为:name 'x' is not defined
run other code...
解释:
原本程序一旦出现异常就结束运行。
有了异常处理后,在被检测的代码块出现异常时,被检测的代码块中,异常发生位置后的代码,将不会执行,取而代之的时执行匹配异常的except子代码块,其余代码均正常运行。
当被检测的代码块中有可能触发不同类型的异常时,针对不同类型的异常:
1、多分支的except
如果我们想分别用不同的逻辑处理,需要用到多分支的except(类似于多分枝的elif,从上到下依次匹配,匹配成功一次便不再匹配其他)
try:
被检测的代码块
except NameError:
触发NameError时对应的处理逻辑
except IndexError:
触发IndexError时对应的处理逻辑
except KeyError:
触发KeyError时对应的处理逻辑
# 举例:
def convert_int(obj):
try:
res=int(obj)
except ValueError as e:
print('ValueError: %s' %e)
res=None
except TypeError as e:
print('TypeError: %s' %e)
res=None
return res
convert_int('egon')
# 输出异常:ValueError: invalid literal for int() with base 10: 'egon'
convert_int({'n':1})
# 输出异常:TypeError: int() argument must be a string, a bytes-like object or a number, not 'dict'
2、一个except
如果我们想多种类型的异常统一用一种逻辑处理,可以将多个异常放到一个元组内,用一个except匹配
try:
被检测的代码块
except (NameError,IndexError,TypeError):
触发NameError或IndexError或TypeError时对应的处理逻辑
# 举例:
def convert_int(obj):
try:
res=int(obj)
except (ValueError,TypeError):
print('argument must be number or numeric string')
res=None
return res
convert_int('egon')
# 输出异常:argument must be number or numeric string
convert_int({'n':1})
# 输出异常:argument must be number or numeric string
3、万能异常类型Exception
如果我们想捕获所有异常并用一种逻辑处理,Python提供了一个万能异常类型Exception
try:
被检测的代码块
except NameError:
触发NameError时对应的处理逻辑
except IndexError:
触发IndexError时对应的处理逻辑
except Exception:
其他类型的异常统一用此处的逻辑处理
4、多分支except…else…
在多分支except之后还可以跟一个else(else必须跟在except之后,不能单独存在),只有在被检测的代码块没有触发任何异常的情况下才会执行else的子代码块
try:
被检测的代码块
except 异常类型1:
pass
except 异常类型2:
pass
......
else:
没有异常发生时执行的代码块
5、try…finally…
此外try还可以与finally连用,从语法上讲finally必须放到else之后,但可以使用try-except-finally的形式,也可以直接使用try-finally的形式。无论被检测的代码块是否触发异常,都会执行finally的子代码块,因此通常在finally的子代码块做一些回收资源的操作,比如关闭打开的文件、关闭数据库连接等
python try:
被检测的代码块
except 异常类型1:
pass
except 异常类型2:
pass
......
else:
没有异常发生时执行的代码块 finally: 无论有无异常发生都会执行的代码块
# 举例:
f=None
try:
f=open(‘db.txt’,'r',encoding='utf-8')
s=f.read().strip()
int(s) # 若字符串s中包含非数字时则会触发异常ValueError
# f.close() # 若上面的代码触发异常,则根本不可能执行到此处的代码,应该将关闭文件的操作放到finally中
finally:
if f: # 文件存在则f的值不为None
f.close()
6、raise
在不符合Python解释器的语法或逻辑规则时,是由Python解释器主动触发的各种类型的异常,而对于违反程序员自定制的各类规则,则需要由程序员自己来明确地触发异常,这就用到了raise语句,raise后必须是一个异常的类或者是异常的实例
class Student:
def __init__(self,name,age):
if not isinstance(name,str):
raise TypeError('name must be str')
if not isinstance(age,int):
raise TypeError('age must be int')
self.name=name
self.age=age
stu1=Student(4573,18) # TypeError: name must be str
stu2=Student('egon','18') # TypeError: age must be int
7、自定义异常类
在内置异常不够用的情况下,我们可以通过继承内置的异常类来自定义异常类
class PoolEmptyError(Exception): # 可以通过继承Exception来定义一个全新的异常
def __init__(self,value='The proxy source is exhausted'): # 可以定制初始化方法
super(PoolEmptyError,self).__init__()
self.value=value
def __str__(self): # 可以定义该方法用来定制触发异常时打印异常值的格式
return '< %s >' %self.value
class NetworkIOError(IOError): # 也可以在特定异常的基础上扩展一个相关的异常
pass
raise PoolEmptyError # __main__.PoolEmptyError: < The proxy source is exhausted >
raise NetworkIOError('连接被拒绝') # __main__.NetworkIOError: 连接被拒绝
8、assert expression
Python还提供了一个断言语句assert expression,断定表达式expression成立,否则触发异常AssertionError,与raise-if-not的语义相同
age='18'
# 若表达式isinstance(age,int)返回值为False则触发异常AssertionError
assert isinstance(age,int)
# 等同于
if not isinstance(age,int):
raise AssertionError
三、何时使用异常处理
1、if
如果错误发生的条件是“可预知的”,用if来进行”预防”
age=input('input your age>>: ').strip()
if age.isdigit(): # 可预知只有满足字符串age是数字的条件,int(age)才不会触发异常,
age=int(age)
else:
print('You must enter the number')
2、try…except
如果错误发生的条件“不可预知”,即异常一定会触发,那么我们才应该使用try…except语句来处理
# 例如我们编写一个下载网页内容的功能,网络发生延迟之类的异常是很正常的事,而我们根本无法预知在满足什么条件的情况下才会出现延迟,因而只能用异常处理机制了
import requests
from requests.exceptions import ConnectTimeout # 导入requests模块内自定义的异常
def get(url):
try:
response=requests.get(url,timeout=3)#超过3秒未下载成功则触发ConnectTimeout异常
res=response.text
except ConnectTimeout:
print('连接请求超时')
res=None
except Exception:
print('网络出现其他异常')
res=None
return res
get('https://www.python.org')