Python中with语句详解:作用、应用场景及其重要性
📌 Python 中的 with 语句:作用 & 什么时候用
1️⃣ with 是干嘛的?
with 主要用来 自动管理资源,确保资源(文件、数据库连接等)在使用完后能自动释放,避免资源泄露问题。
换句话说:
with:你要自己手动释放资源,容易忘记,出 bug。with:Python 会自动帮你释放资源,不用操心。2️⃣ 什么时候需要 with?
凡是涉及:
✅ 打开文件
✅ 数据库连接
✅ 网络请求
✅ 多线程锁
✅ 临时性资源管理
这些场景都应该用 with!
3️⃣ 举例说明
(1)文件操作
❌ 不使用 with,容易忘记关闭文件:
file = open("data.txt", "r")
data = file.read()
file.close() # 🔴 你必须手动关闭文件
如果 忘了 file.close(),可能会导致 文件一直占用,影响其他程序访问。
✅ 使用 with,自动关闭文件
with open("data.txt", "r") as file:
data = file.read() # ✅ 读完后,Python 自动关闭文件
with 结束后,文件 file 会自动关闭!
(2)数据库操作
❌ 不使用 with,可能忘记关闭数据库连接
import sqlite3
conn = sqlite3.connect("example.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
data = cursor.fetchall()
conn.close() # 🔴 必须手动关闭连接
如果程序出错,中途 return 了,conn.close() 可能不会执行,导致数据库连接泄露!
✅ 使用 with,自动管理数据库连接
import sqlite3
with sqlite3.connect("example.db") as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
data = cursor.fetchall() # ✅ 退出 `with` 代码块时,数据库连接自动关闭!
好处:
close(),更安全with 也会自动关闭数据库(3)网络请求
❌ 不使用 with,请求未关闭
import requests
response = requests.get("https://www.example.com")
data = response.text
response.close() # 🔴 必须手动关闭连接
如果忘了 response.close(),可能会占用网络资源,影响其他请求。
✅ 使用 with,自动关闭请求
import requests
with requests.get("https://www.example.com") as response:
data = response.text # ✅ 退出 `with`,自动关闭请求
(4)多线程锁
在多线程编程中,我们需要使用 Lock 来保证数据安全。
但如果忘记释放 lock,程序可能会死锁!
✅ 使用 with,确保锁释放
import threading
lock = threading.Lock()
with lock: # ✅ 进入 `with`,加锁
print("线程安全的代码")
# ✅ 退出 `with`,自动释放锁
4️⃣ with 语法是如何工作的?
with 其实是调用对象的 __enter__() 和 __exit__() 方法,确保资源正确释放:
class MyResource:
def __enter__(self):
print("资源已获取")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("资源已释放")
with MyResource():
print("使用资源中...")
输出:
资源已获取
使用资源中...
资源已释放
结论: 只要 with 结束,Python 自动调用 __exit__() 释放资源,不用手动操作。
5️⃣ 结论
✅ with 主要用于 自动管理资源,避免手动释放资源的麻烦。
✅ 避免资源泄露,减少 bug,即使代码中途出错,也能自动清理资源。
✅ 常用于:
💡 记住:凡是涉及“打开 -> 使用 -> 关闭”的场景,都应该用 with! 🚀
📌 with 结束的时机是什么时候?
with 语句的结束时机,简单来说,就是**with 代码块执行完毕**,或者在 with 代码块中发生异常时。
具体来说,with 语句在退出代码块时,会触发资源的自动清理,也就是调用 __exit__() 方法。
1️⃣ 具体的结束时机
✅ 情况 1:正常执行完代码块
如果 with 代码块里的代码正常执行完,就会自动调用 __exit__() 方法释放资源,with 语句结束。
🔹 示例:文件操作
with open("test.txt", "w") as f:
f.write("Hello, world!") # ✅ 正常执行完 `write`
# `with` 结束,文件自动关闭
结束时机: f.write() 执行完,with 退出,文件自动关闭。
✅ 情况 2:发生异常,with 也会立即结束
如果 with 代码块里发生异常,with 语句会立刻调用 __exit__() 进行清理,然后抛出异常(除非 __exit__() 处理了异常)。
🔹 示例:发生异常
try:
with open("test.txt", "w") as f:
f.write("Hello, world!")
1 / 0 # ❌ 人为制造异常
except ZeroDivisionError:
print("发生错误,文件已经关闭")
结束时机: 1 / 0 抛出异常时,with 立刻结束,文件自动关闭。
✅ 情况 3:return 也会触发 with 结束
如果 with 代码块里遇到 return,break,continue,with 也会立即结束,并释放资源。
🔹 示例:return 触发 with 结束
def write_file():
with open("test.txt", "w") as f:
f.write("Hello, world!")
return # ✅ `return` 触发 `with` 结束
结束时机: return 触发 with 结束,文件自动关闭。
2️⃣ with 结束的底层原理
当 with 语句执行时,它的工作流程如下:
- 进入
with:调用__enter__()方法,获取资源。 - 执行代码块:执行
with代码块里的内容。 - 退出
with: - 正常结束:执行
__exit__(),释放资源。 - 发生异常:
- 如果
__exit__()处理异常,则with正常结束。 - 如果
__exit__()没有处理异常,异常会继续向上抛出。
🔹 示例:自定义 with 语句行为
class MyContext:
def __enter__(self):
print("进入 `with` 语句")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出 `with` 语句")
if exc_type:
print(f"发生异常:{exc_val}")
return True # 处理异常,不抛出
with MyContext():
print("执行 `with` 代码块")
1 / 0 # ❌ 发生异常
print("代码继续执行")
输出:
进入 `with` 语句
执行 `with` 代码块
退出 `with` 语句
发生异常:division by zero
代码继续执行
分析:
1 / 0 触发异常,with 立刻结束,调用 __exit__() 处理。__exit__() 返回 True,异常被处理,不会向上传播。3️⃣ 总结
✅ with 语句的结束时机:
- 正常执行完代码块(执行完最后一行)。
- 遇到异常,
with立刻结束,并调用__exit__()释放资源。 - 遇到
return、break、continue,with立刻结束,资源被释放。
💡 简单记住:with 一旦代码块结束或发生异常,就立刻释放资源,自动退出! 🚀
作者:背太阳的牧羊人