Python开发-032_异常处理
在程序开发中,如果遇到一些不可预知的错误,或者懒得判断处理的错误,可以使用异常处理来完成
例如:我们需要下载一个网站的页面
import requests
while True:
url = input("请输入需要下载的网址:")
res = requests.get(url=url)
with open("demo.html",mode="wb") as file:
file.write(res.content)
正常情绪下直接下载没有问题,但是如果网络中断,那么程序就会导致报错,导致程序直接崩溃,并且抛出报错requests.exceptions.ConnectionError:HTTPConnectionPool
1 异常处理的基本格式
try:
# 逻辑代码
except Exception as e: # e是一个对象,包含了res的错误信息
# try中的代码如果有异常,则此代码块中的代码会执行。
直接对上面的程序进行套用
import requests
while True:
url = input("请输入需要下载的网址:")
try:
res = requests.get(url=url)
except Exception as e:
print("请求失败,原因是{}".format(str(e)))
continue
with open("demo.html", mode="wb") as file:
file.write(res.content)
这样,即显示了错误,也不会将程序给崩溃掉,他的应用场景还常用于傻逼用户的异想天开输入
num1 = input("请输入一个数字:")
num2 = input("请再输入一个数字:")
try:
num1 = int(num1)
num2 = int(num2)
result = num1 + num2
print(result)
except Exception as e:
print("傻逼们又瞎几把输入什么?")
以后常见的应用场景:
-
调用微信的API实现微信消息的推送、微信支付等
-
支付宝支付、视频播放等
-
数据库 或 redis连接和操作
-
调用第三方的视频播放发的功能,由第三方的程序出问题导致的错误。
2 try.except_as_e.finally
此方法有点像if...else...
语句,则try中的代码无论是否报错,finally中的代码都会执行
try:
# 逻辑代码
except Exception as e:
# try中的代码如果有异常,则此代码块中的代码会执行。
finally:
# try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。
print("end")
一般用于释放资源
try:
file_object = open("xxx.log")
# ....
except Exception as e:
# 异常处理
finally:
file_object.close()
# try中没异常,最后执行finally关闭文件;try有异常,执行except中的逻辑,最后再执行finally关闭文件。
3 异常细分
之前只是简单的捕获了异常,出现异常则统一提示信息即可。如果想要对异常进行更加细致的异常处理,则可以这样来做:
import requests
from requests import exceptions
while True:
url = input("请输入要下载网页地址:")
try:
res = requests.get(url=url)
print(res)
except exceptions.MissingSchema as e: # 通过捕获不同的异常来执行不同的代码
print("URL架构不存在")
except exceptions.InvalidSchema as e:
print("URL架构错误")
except exceptions.InvalidURL as e:
print("URL地址格式错误")
except exceptions.ConnectionError as e: # 在前文演示中就是捕获了ConnectionError异常
print("网络连接错误")
except Exception as e:
print("代码出现错误", e)
# 提示:如果想要写的简单一点,其实只写一个Exception捕获所有错误就可以了。
Python中内置了很多细分的错误
常见异常:
"""
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问n x[5]
KeyError 试图访问字典里不存在的键 inf['xx']
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
"""
更多异常:
"""
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
"""
4 自定义异常&抛出异常
之前我们介绍的都是Python内置的异常,其实我们也可以自定义异常
class MyException(Exception):
# 自定义异常需要继承原有异常
pass
# 捕获异常的代码
try:
pass
except MyException as e:
print("自定义异常被触发了",e)
except Exception as e:
print("Exception",e)
上述代码在except
中定义了捕获MyException
异常,但他永远不会被触发。因为默认的那些异常都会raise
特定的触发条件,例如:索引不存在、键不存在会触发IndexError
和KeyError
异常
对于我们自定义的异常,如果想要触发,则需要使用:raise
丢出MyException()
报错实现,然后再使用except MyException as e:
捕获到这个异常
# 案例
# 方式一
class MyException(Exception):
# 自定义异常继承原有异常
def __init__(self,msg,*args,**kwargs):
super().__init__(*args,**kwargs) # 调用Exception的__init__功能
self.msg = msg # 给Exception的__init__增加一个msg的变量
# 方式二
class MytException(Exception):
title = "这是MytException异常类"
# 捕获异常的代码
msg = input("msg:")
try:
if msg:
raise MyException(msg) # 丢出MyException报错
# raise执行后,下方代码不会再执行了
raise MytException # 丢出MytException报错
except MyException as e:
print("自定义异常MyException被触发了",e.msg)
except MytException as e:
print(e.title)
案例:邮件发送
import smtplib,re
from email.mime.text import MIMEText
from email.utils import formataddr
class EmailValidError(Exception):
titile = "邮件格式错误"
class ContentRequiredError(Exception):
title = "文件内容不能为空"
def send_emali(emali,content):
if not re.match("\w+@+\w+.+\w",emali):
raise EmailValidError()
if len(content) == 0:
raise ContentRequiredError()
msg = MIMEText(content,'html','utf-8') # content 文件内容
msg['From'] = formataddr(["kinght测试",'kinght@geekxk.com'])
msg['Subject'] = content # 文件标题
server = smtplib.SMTP_SSL('smtp.exmail.qq.com')
server.login("kinght@geekxk.com","密码") # 个别邮箱需要使用专门的授权码
server.sendmail("kinght@geekxk.com",emali,msg.as_string())
server.quit()
def execute():
try:
send_emali("419353653@qq.com",'20220702测试')
except EmailValidError as e:
print(e.titile)
except ContentRequiredError as e:
print(e.title)
except Exception as e:
print(e)
execute()
5 特殊的finally
之前提到过try中的代码无论是否报错,finally中的代码都会执行,那么finally存在的意义是什么?
def func():
try:
return 123
except Exception as e:
pass
finally:
print(666) # 会得到输出
print(777) # 不会得到输出
func()
在try或except中即使定义了return,也会执行最后的finally块中的代码,然后再返回return
def func():
print(666)
return "成功" # 第二步返回成功
def run(handler):
try:
num = handler()
print(num)
return func() # 第一步执行func()中函数 第四步执行return进行返回
except Exception as e:
return "失败"
finally: # 第三步发现有finally,在返回try中的值之前执行finally语句
print("END")
print("结束")
res = run(lambda : 123)
print(res)
'''
123
666
END
成功
'''