with 语句是 Python 中用于资源管理的优雅语法结构,它通过上下文管理器确保资源被正确获取和释放,即使发生异常也能安全清理。
核心概念
1. with 语句的基本用法
python
# 文件操作的标准写法
with open('file.txt', 'r') as f:
content = f.read()
# 文件会自动关闭,无需显式调用 f.close()
2. 上下文管理器(Context Manager)
上下文管理器是实现了 __enter__() 和 __exit__() 方法的对象:
python
class MyContextManager:
def __enter__(self):
print("进入上下文 - 资源分配")
return self # 返回的资源对象会被 as 接收
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文 - 资源清理")
if exc_type: # 如果有异常
print(f"异常类型: {exc_type}")
return False # False 会传播异常,True 会抑制异常
# 使用
with MyContextManager() as cm:
print("执行代码块")
3. contextlib 简化创建
使用标准库的 contextlib 模块可以更简洁地创建上下文管理器:
python
from contextlib import contextmanager
@contextmanager
def timer():
import time
start = time.time()
try:
yield # 在此处暂停,执行 with 代码块
finally:
end = time.time()
print(f"耗时: {end - start:.2f}秒")
with timer():
import time
time.sleep(1)
工作原理
执行流程
python
# 1. 调用 __enter__() 方法
# 2. 执行 with 代码块
# 3. 调用 __exit__() 方法(即使发生异常也会执行)
# 4. 如果发生异常,异常信息会传递给 __exit__()
with MyResource() as resource:
# 此处是安全的代码区域
do_something()
# 此处资源已被清理
实际应用场景
1. 数据库连接管理
python
class DatabaseConnection:
def __enter__(self):
self.conn = create_connection()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
self.conn.close()
with DatabaseConnection() as db:
db.execute_query("SELECT * FROM users")
2. 临时状态管理
python
import sys
from contextlib import redirect_stdout
with open('output.txt', 'w') as f:
with redirect_stdout(f): # 临时重定向标准输出
print("这段文字会写入文件")
print("这段文字输出到控制台")
3. 锁管理
python
import threading
lock = threading.Lock()
with lock: # 自动获取和释放锁
# 线程安全的代码块
shared_data.append(item)
内置上下文管理器示例
| 类型 | 示例 | 说明 |
|---|---|---|
| 文件 | with open(...) as f |
自动关闭文件 |
| 锁 | with threading.Lock() |
自动释放锁 |
| 重定向 | with redirect_stdout() |
临时重定向输出 |
| 数据库 | with connection.cursor() |
自动提交/回滚 |
| Decimal | with decimal.localcontext() |
临时修改精度 |
高级用法
多个上下文管理器
python
# 可以同时管理多个资源
with open('input.txt', 'r') as f1, \
open('output.txt', 'w') as f2:
content = f1.read()
f2.write(content.upper())
异常处理整合
python
class Transaction:
def __enter__(self):
self.begin_transaction()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type: # 发生异常
self.rollback()
else: # 正常执行
self.commit()
with Transaction() as txn:
txn.execute("UPDATE accounts SET balance = ...")
# 如果这里发生异常,会自动回滚
最佳实践
- 优先使用 with :处理需要清理的资源时,总是优先使用
with语句 - 保持简单:上下文管理器应专注于单一资源的生命周期管理
- 正确处理异常 :在
__exit__中根据异常情况决定是否传播异常 - 组合使用 :使用
contextlib.ExitStack管理动态数量的上下文管理器
python
from contextlib import ExitStack
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# 所有文件都会在退出时正确关闭
总结
with 语句和上下文管理器是 Python 的重要语法糖,它们:
- ✅ 确保资源被正确释放
- ✅ 减少代码冗余(避免 try-finally 模板代码)
- ✅ 提高代码可读性
- ✅ 统一异常处理逻辑
- ✅ 支持多种资源类型(文件、锁、连接等)
这是 Python 实现RAII(资源获取即初始化) 模式的主要方式,是编写健壮、安全代码的关键工具。