with语句通过上下文管理器协议确保资源在进入和退出代码块时被正确初始化和清理,即使发生异常也能自动释放资源,从而避免资源泄漏;它通过__enter__和__exit__方法或contextlib的@contextmanager装饰器实现,使文件、数据库连接等资源管理更安全、简洁。

with
在编程实践中,我们经常需要处理一些有“生命周期”的资源:打开文件后要关闭,连接数据库后要断开,获取锁后要释放。如果手动去管理这些步骤,尤其是在代码路径复杂或者出现异常的情况下,很容易遗漏清理操作,导致资源泄漏或者程序行为异常。
with
with
with
我记得刚开始写Python的时候,处理文件都是这样:
f = open('my_file.txt', 'r'); data = f.read(); f.close()f.read()
f.close()
return
return
f.close()
这就是
with
拿文件操作来说,当你写
with open('my_file.txt', 'r') as f:f
with
f.close()
try...finally
数据库连接也是一个典型的例子。连接池中的连接是宝贵的资源,一个应用如果不断地获取连接而不释放,很快就会把连接池耗尽,导致其他请求无法获取连接。使用
with
实现一个自定义的上下文管理器,其实就是让你的类遵循上下文管理器协议,也就是实现两个特殊方法:
__enter__
__exit__
__enter__(self)
with
as
with MyResource() as res:
res
MyResource
__enter__
__enter__
self
__exit__(self, exc_type, exc_val, exc_tb)
with
exc_type
with
ValueError
None
exc_val
None
exc_tb
None
在
__exit__
exc_type
None
with
__exit__
__exit__
True
True
False
None
False
举个例子,假设我们要实现一个简单的计时器上下文管理器:
import time
class MyTimer:
def __enter__(self):
self.start_time = time.time()
print("计时开始...")
return self # 返回自身实例,这样 with MyTimer() as timer: 就可以用 timer 了
def __exit__(self, exc_type, exc_val, exc_tb):
end_time = time.time()
duration = end_time - self.start_time
print(f"计时结束,总耗时:{duration:.4f} 秒")
if exc_type: # 如果有异常发生
print(f"with 块内发生异常:{exc_type.__name__}: {exc_val}")
# 如果我们不想让异常继续传播,可以在这里返回 True
# return True
# 默认返回 None,即 False,异常会继续传播
print("资源清理完成。")
# 使用示例
with MyTimer():
print("正在执行一些耗时操作...")
time.sleep(1.5)
# raise ValueError("哦豁,出错了!") # 尝试解注释这行看看异常处理
print("with 块外部代码继续执行。")这里
__enter__
self
with MyTimer() as timer:
timer
MyTimer
__exit__
contextlib
说实话,每次都写一个类,然后实现
__enter__
__exit__
contextlib
@contextmanager
@contextmanager
yield
__enter__
yield
__enter__
yield
__exit__
我们来用
@contextmanager
from contextlib import contextmanager
import time
@contextmanager
def simple_timer():
start_time = time.time()
print("计时开始 (通过 contextlib)...")
try:
yield # 这里是 with 块的代码执行的地方
except Exception as e:
print(f"with 块内发生异常 (通过 contextlib):{type(e).__name__}: {e}")
# 如果要抑制异常,这里可以不 re-raise,或者捕获后不抛出
# 也可以再次抛出,或者抛出新的异常
raise # 默认会重新抛出捕获到的异常
finally:
end_time = time.time()
duration = end_time - start_time
print(f"计时结束 (通过 contextlib),总耗时:{duration:.4f} 秒")
print("资源清理完成 (通过 contextlib)。")
# 使用示例
with simple_timer():
print("正在执行一些耗时操作 (通过 contextlib)...")
time.sleep(0.8)
# raise TypeError("又出错了!") # 尝试解注释这行
print("with 块外部代码继续执行 (通过 contextlib)。")你看,是不是简洁多了?一个函数搞定一切。
yield
__enter__
__exit__
try...except...finally
yield
yield
try...except
except
except
finally
以上就是with 语句和上下文管理器(Context Manager)的原理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号