<摘要>
生产环境里,很多“文件句柄耗尽”或“数据库连接池爆满”的事故,
并不是代码逻辑太复杂,而是异常发生时资源没有正确释放,
平时代码里,这类问题占了相当大的比例。
Python 中处理这类问题最简单有效的方式,就是用 with 语句,
它让资源自动管理,不容易出错。
1. 最容易出问题的写法
f = open('data.txt', 'w')f.write('Hello World')# 如果这行代码出错了,下面的 close 永远不会执行!do_something_complex()f.close()文件没关,句柄一直占用,时间长了系统就会报错。
2. 加上 try-finally 的写法
f = open('data.txt', 'w')try:f.write('Hello World')do_something_complex()finally:# 无论是否报错,这里都会执行f.close()这样即使出异常,文件也会关闭。安全,但代码多几行,缩进也多,写起来不方便。
3. 用 with 的写法
withopen('data.txt', 'w') as f:f.write('Hello World')do_something_complex()# 出了缩进块,文件自动关闭。哪怕报错,也自动关闭。with 块结束时,文件自动关闭。正常结束会关,抛异常也会关。代码短,逻辑清楚。
4、with 是怎么实现的
为什么 with 这么聪明?它到底在背后干了什么?
通俗点说,with 语句通过一种协议,强制对象必须遵守“进门登记”和“出门销户”的规则。
这涉及到两个特殊方法:
- __enter__:进入 with 块时调用,通常用来获取资源(打开文件、连接数据库等)。
- __exit__:离开 with 块时调用(不管正常结束还是异常),通常用来释放资源(关闭文件、断开连接等)。
你可以把它想象成酒店的“插卡取电”系统:
你进房间(Enter),插卡,通电;
你离开房间(Exit),拔卡,断电。
只要你人不在房间了,电一定会断。 这就是确定性。
5、 同时处理多个资源(Python 3.10+ 的写法)
在以前,如果你需要同时打开两个文件(比如把 A 文件内容读出来写入 B 文件),你可能会写嵌套:
# 旧时代的写法with open('input.txt') as fin:with open('output.txt', 'w') as fout:fout.write(fin.read())这不仅难看,而且随着层级增加,代码会不断向右平移。
Python 3.10 引入了“带括号的上下文管理器” (Parenthesized context managers)。
# Python 3.10+ 新潮写法with (open('input.txt', 'r') as fin,open('output.txt', 'w') as foutfout.write(fin.read())代码更平整,好读。建议用新写法。
6、 避坑指南
with 不创建作用域!
很多类似 C++ 或 Java 的语言,花括号 {} 内定义的变量在外部无法访问。但 Python 的 with 不同。所以变量名要避免和外面冲突。
with open('test.txt') as f:content = "Secret Data"print(content) # 竟然能打印出来!输出:Secret Dataprint(f) # 文件对象也还在!(虽然已经处于 closed 状态)特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.