异常处理
了解如何在 Python 后端开发中处理异常。
异常处理
>>> print(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined这是我们经常看到的程序运行出现的错误.
异常时一个事件,该事件会在程序执行过程中发生,影响程序的正常执行.
在python中的异常其实是一个类,都继承了Exception基类.
如何使用异常
如果python中的代码出现异常,但是不想让程序出现崩溃的做法
def exp_exception(a, b):
return a / b
if __name__ == '__main__':
print(exp_exception(1, 0)) # 如果代码产生异常,可能会导致程序异常退出我们可以使用
try:
# 需要执行的代码段
pass
except Exception as e:
# 如果执行的代码块出现了异常,则在 except 中执行自己定义的出错逻辑
print(e)来进行捕获异常
def exp_exception(a, b):
return a / b
if __name__ == '__main__':
try: # 用来检测当前要执行的代码是否有异常
print(exp_exception(1, 0)) # 如果代码产生异常,可能会导致程序异常退出
except ZeroDivisionError as e: # 如果 try 代码块中的代码执行出现了异常则进行捕获
print(e)
print("除法中除数不能为 0")
pass结果:
division by zero
除法中除数不能为 0如果不知道会出现什么异常,这里except后面的是可以忽略不写的,或者直接写基类Exception.
def exp_exception(a, b):
if b == 0:
raise ZeroDivisionError("除数不能为 0")
return a / b
if __name__ == '__main__':
try: # 用来检测当前要执行的代码是否有异常
print(exp_exception(1, 0)) # 如果代码产生异常,可能会导致程序异常退出
except ZeroDivisionError as e: # 如果 try 代码块中的代码执行出现了异常则进行捕获
print(e)
print("除法中除数不能为 0")
pass
except ZeroDivisionError as e这里的as e是把捕获到的异常赋值给变量e,方便我们在except代码块中使用.
常见的会出现异常的地方
- 文件读写
- 数据库链接
- 云服务器链接
你在去运行代码的时候已经发现了程序错误了,但是不想因为这个错误导致程序中断,这个时候就可以使用异常了.
注意点
线程里面不能使用try except 来捕获异常,否则会导致线程无法终止.
断言
定义
在执行一段代码时,可以加上判断,如果判断的结果和设置的结果不一致则抛出异常.
爬虫中用的比较多
"""
案例:访问一个网站,如果访问的网站返回的状态码不是 200 则故意抛出异常
前提: pip install requests
"""
import requests
url = "https://www.baidu.com/user_name/lalala"
response = requests.get(url)
assert response.status_code == 200, StopIteration # 自己抛出了一个异常,可以根据要求进行自我更改assert和raise的区别:
assert是断言,用来判断某个条件是否成立,如果不成立则抛出异常.raise是用来主动抛出一个异常.是没有条件的
finally
在代码执行的过程中如果出现了异常,并且出现异常之后还需要执行其他代码则可以使用finally实现
try:
print(9 / 3)
except Exception as e:
print(e)
else:
print("ok")
finally:
print("无论代码是否发生异常都必须执行当前语句")结果:
3.0
ok
无论代码是否发生异常都必须执行当前语句使用场景
一般用于我们的数据库的读写操作,无论数据库的读写是否成功,都需要关闭数据库连接.
try:
self.cursor.execute(sql, args)
# 事务提交
self.db.commit()
print("执行成功")
except Exception as e:
print('数据插入失败')
finally:
# 事务回滚
self.db.rollback() # 注意: 这里不能 self.db.close()用的较多的场景:
- 数据存储
- 文件读写
自定义异常
class LoginError(Exception):
def __str__(self):
"""通过 print 来触发的方法"""
return '用户名或密码错误'
def __repr__(self):
return "用户名或密码错误"
name = input('请输入用户名')
password = input('请输入密码')
local_name = '无解'
local_password = '123456'
try:
if name != local_name or password != local_password:
# 手动抛出异常
raise LoginError
except LoginError as e:
print(e)
if password == local_password and name == local_name:
print('登录成功')
else:
print('登录失败')结果
请输入用户名dwqdqwdwq
请输入密码dwqdqw
用户名或密码错误
登录失败注意
自定义异常一定要继承 Exception
__repr__注意是用在交互式命令行中显示对象信息的,而__str__是用在print函数中显示对象信息的.
这里用到了ipython
pip install ipython
# 或者
pip install ipython -i https://pypi.douban.com/simple In [1]: class Test:
...: def __str__(self):
...: return 'abc'
...:
In [2]: test = Test()
In [3]: print(test)
abc
In [4]: test
Out[4]: <__main__.Test at 0x109970590>
In [5]: class Test:
...: def __repr__(self):
...: return 'abc'
...:
In [6]: test = Test()
In [7]: test
Out[7]: abc文件内容读取
# -*- coding: utf-8 -*-
"""
@File : 文本文件中的内容读取.py
@Author : wxvirus
@Time : 2026/1/22 21:12
@Desc : 完成文本文件中的内容读取: 测试文件.txt
"""
"""
python 的内置函数:
open(): 返回一个对象,称之为文件对象
文件对象中提供了内容读取的方法: read()
"""
# 1. 定义当前文件的路径(路径一般都是写相对路径)
file_path = './测试文件.txt'
file_obj = open(file_path, 'r', encoding='utf-8')
# 2. 使用文件对象进行内容读取
print(file_obj.read())
print(file_obj.readlines()) # 返回的是一个列表
# 释放计算机资源
file_obj.close() # 如果不释放,文件对象越积越多,可能会内存溢出,程序闪退或者崩溃了open()的第二个参数mode有四种常用的模式:
r: 以只读的方式打开文件,文件的指针放在w: 以写入的方式打开文件,如果文件存在则覆盖,如果文件不存在则创建a: 以追加的方式打开文件,如果文件存在则在文件末尾进行追加,如果文件不存在则创建w+: 以读写的方式打开文件,如果文件存在则覆盖,如果文件不存在则创建b: 以二进制的方式打开文件,一般用于图片的读,会有rb和wb两种模式,分别表示读和写,还有wb+表示读写,ab表示追加.
# 3. 使用文件对象进行内容写入
write_obj = open(file_path, 'w', encoding='utf-8') # 覆盖式写入
write_obj.write('晚上一起写代码')
# 4. 使用文件对象进行内容追加
write_obj = open(file_path, 'a', encoding='utf-8') # 追加写入
write_obj.write('晚上一起写代码\ndwqdwqdwq') # 写入换行
stu_name_list = ['无解', '哈哈', '?\n']
# writelines 可以传一个可迭代的对象
# 多行写,写多行
write_obj.writelines(stu_name_list)with open(file_path, 'r', encoding='utf-8') as file_obj:
# 在上下文管理器当中,是不需要主动 close() 的
print(file_obj.read())自定义类完成文件读写
# -*- coding: utf-8 -*-
"""
@File : 自定义类完成文件读写.py
@Author : wxvirus
@Time : 2026/1/22 21:37
@Desc :
"""
class MyOpenFile:
def __init__(self, file_path):
self.file_obj = None
self.file_path = file_path
def __enter__(self):
print('即将创建文件对象...')
self.file_obj = open(self.file_path, 'r', encoding='utf-8')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""退出的时候调用"""
print('即将释放文件对象...')
self.file_obj.close()
def my_read(self):
"""打印读取的内容"""
print(self.file_obj.read())
with MyOpenFile('./测试文件.txt') as file:
file.my_read()结果
即将创建文件对象...
晚上一起写代码晚上一起写代码
dwqdwqdwq晚上一起写代码
dwqdwqdwq无解哈哈?
晚上一起写代码
dwqdwqdwq无解哈哈?
即将释放文件对象...使用w+同一个文件对象进行文件读写
with open('./测试文件.txt', 'w+', encoding='utf-8') as file:
file.write('今天天气不错...')
# 将游标归为
file.seek(0)
# 不归位,这里则读取不到写入的内容,因为游标已经在文件末尾了
print(file.read())二进制文件写入
# -*- coding: utf-8 -*-
"""
@File : 二进制文件写入.py
@Author : wxvirus
@Time : 2026/1/22 21:47
@Desc :
"""
import requests
response = requests.get("https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png")
# 二进制文件写入
with open('baidu.png', 'wb') as f:
f.write(response.content)