Context (上下文)
以下是一份 最清晰、最全面、最实战的 Python“上下文(Context)”指南,包括:
- Python“上下文”到底是什么?
- with 是如何工作的?
- 什么叫上下文管理器?
- 上下文的真实应用场景?
- 如何自定义上下文管理器?
这是学习 Python 进阶必须掌握的重点。
在 Python 中:
上下文(context)= 一个代码块运行时的环境 + 进入/退出时的逻辑
最典型的例子:
with open("a.txt") as f:
data = f.read()
执行流程是:
- 进入上下文(打开文件)
- 执行代码块
- 离开上下文(自动关闭文件)
所以:
📝 “上下文” = 执行某段代码时,自动帮你管理资源的机制
要成为上下文管理器,必须实现两个魔法方法:
| 方法 | 作用 |
|---|---|
__enter__(self) |
将对象“放入”上下文,返回给 as |
__exit__(self, exc_type, exc, tb) |
离开上下文时自动执行清理 |
示例:
class MyCtx:
def __enter__(self):
print("进入上下文")
return "OK"
def __exit__(self, exc_type, exc, tb):
print("退出上下文")
with MyCtx() as v:
print(v)
输出:
进入上下文
OK
退出上下文
上下文用于自动资源管理:
| 场景 | 原因 |
|---|---|
| 文件读写 | 自动关闭文件句柄 |
| 数据库连接 | 自动提交 / 回滚 |
| 加锁 | 自动加锁/解锁 |
| 网络连接 | 自动释放资源 |
| 临时切换状态 | 自动恢复环境 |
| decimal 精度控制 | 执行结束后恢复配置 |
上下文 = 自动化的“进入 -> 退出流程”,减少错误。
with open('a.txt') as f:
with threading.Lock():
with conn:
conn.execute(sql)
from decimal import localcontext
with localcontext() as ctx:
ctx.prec = 50
from contextlib import chdir
with chdir("/tmp"):
from contextlib import suppress
with suppress(FileNotFoundError):
open("abc.txt").read()
from contextlib import redirect_stdout
with open("log.txt", "w") as f:
with redirect_stdout(f):
print("hello")
from contextlib import contextmanager
@contextmanager
def myctx():
print("进入")
yield
print("退出")
with myctx():
print("处理中")
相当于:
- yield 前 =
__enter__ - yield 后 =
__exit__
例如,实现一个“日志计时器”:
import time
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, exc_type, exc, tb):
self.end = time.time()
self.cost = self.end - self.start
print(f"耗时:{self.cost:.4f} 秒")
with Timer() as t:
sum(range(10_0000))
如果 __exit__ 返回 True,异常会被“吞掉”。
class SuppressError:
def __exit__(self, exc_type, exc, tb):
return True # 表示“异常已处理”
with SuppressError():
raise ValueError("oops") # 不会报错
下面两段代码等价:
使用 with:
with open("a.txt") as f:
data = f.read()
等价于 try/finally:
f = open("a.txt")
try:
data = f.read()
finally:
f.close()
📌 with 是 try/finally 的语法糖,但更优雅、更安全。
上下文 = 自动管理资源的机制
with = 自动执行 进入逻辑(enter) + 退出逻辑(exit)
你只需要写代码主体,其余自动完成。