
能嵌套,而且很常见。Python 的 with 语句支持多层嵌套,也支持单行多个上下文管理器(逗号分隔),两者语义略有不同,但都用于安全地管理多个资源。
多层 with 嵌套(缩进式)
这是最直观的嵌套方式,适合逻辑上存在先后依赖、或需要分别处理异常/退出顺序的场景。内层 with 块执行完才退出外层。
- 每个
with独立调用__enter__和__exit__ - 退出顺序与进入顺序相反(后进先出),即内层先退出,外层后退出
- 适用于需按特定顺序打开/关闭资源,比如先连数据库再开事务,或嵌套文件处理
示例:
with open('config.txt') as f1:
config = f1.read()
with open('output.txt', 'w') as f2:
f2.write(config.upper())
这里 f2 一定在 f1 仍有效时被打开,且 f2 关闭后 f1 才继续执行后续(如有)并关闭。
立即学习“Python免费学习笔记(深入)”;
单行多个上下文(逗号分隔)
从 Python 3.1 起支持,在一个 with 语句中同时管理多个独立资源,等价于嵌套但更扁平。
- 所有上下文管理器的
__enter__按从左到右顺序调用 - 所有
__exit__按从右到左顺序调用(和嵌套一致) - 任一
__enter__失败,已成功进入的会按逆序自动退出
示例:
with open('in.txt') as f1, open('out.txt', 'w') as f2, open('log.txt', 'a') as log:
data = f1.read()
f2.write(data[::-1])
log.write('reversed done\n')
三个文件同时打开,任意一个打开失败(如权限不足),前面已打开的会自动安全关闭。
嵌套 with 的实用注意点
不是所有情况都推荐嵌套——关键看资源间是否真有依赖或顺序要求。
- 若资源完全独立,优先用逗号写法,代码更简洁、可读性更好
- 若内层操作依赖外层结果(如用配置决定打开哪个文件),用缩进嵌套更自然
- 避免过深嵌套(超过 3 层),可提取成函数或使用逗号合并
- 自定义上下文管理器要确保
__exit__正确处理异常传播(返回True吞异常,否则向上抛)
和 try/finally 对比的优势
嵌套 with 的核心价值是自动、确定性的资源清理,无需手动配对 close() 或 finally 块。
- 即使中间发生异常、
return、break,资源仍保证释放 - 比手写多层
try/finally简洁得多,不易出错 - 标准库中
open、threading.Lock、contextlib.closing等都原生支持
不复杂但容易忽略:嵌套本质是语法糖,底层靠的是上下文管理器协议,只要对象实现了 __enter__ 和 __exit__,就能参与嵌套或逗号组合。










