网易首页 > 网易号 > 正文 申请入驻

为什么Python大神都在用with?看完我悟了

0
分享至

你有没有遇到过这种崩溃的情况:

f = open('data.txt', 'w')f.write('重要数据')# 程序在这里崩了,文件没关闭!

然后你发现文件损坏了,数据丢了,客户在骂娘,老板在瞪你...

更绝的是这种情况:

conn = sqlite3.connect('database.db')cursor = conn.cursor()cursor.execute('UPDATE users SET money = money + 1000 WHERE id = 1') #后端 #每天一个知识点# 这里抛异常了,连接没关闭,数据库锁死了!

整个应用卡住,用户投诉电话被打爆,你在凌晨3点重启服务器...

今天咱们就来彻底搞懂 Python 的 with 语句,让你告别这些资源泄漏的噩梦。

什么是with语句?

简单来说,with 语句就是 Python 的"自动保姆"。

它会在你使用资源的时候自动打开,用完了自动关闭,中间出异常了也自动关闭。

就像雇了个保姆,你出门前告诉他"帮我照顾孩子",你回家时孩子已经被哄睡着了,不管中间孩子怎么闹腾,保姆都搞定了。

没用with的惨痛教训 ❌ 新手写法(我当年也这么写过)

def process_data():    file = open('important.txt', 'w')    File.write('关键数据')    # 忘记关闭文件了!# 文件句柄泄漏,系统资源被占用

结果: 文件可能没保存成功,其他程序无法访问这个文件。

❌ 进阶写法(看起来很安全,实则坑爹)

def process_data():    try:        file = open('important.txt', 'w')        file.write('关键数据')        # 这里如果抛异常,file.close()不会执行!1 / 0 # 假设这里出异常了file.close() except Exception as e: print(f'出错了: {e}') # 文件没关闭!资源泄漏!

结果: 异常处理了,但资源没释放。

C ❌ 老手写法(终于知道要close了)

def process_data():    try:        file = open('important.txt', 'w')        file.write('关键数据')    except Exception as e:        print(f'出错了: {e}')    finally:        file.close()  # 但是如果open就失败了怎么办?

结果: 如果 open('important.txt') 本身就失败,file.close() 会报错 NameError !

with语句的正确姿势 ✅ 大神写法(优雅、安全、简洁)

def process_data():    with open('important.txt', 'w') as file:        file.write('关键数据')        1 / 0  # 就算这里崩了,文件也会自动关闭

就这么简单!不管中间发生什么,文件都会被正确关闭。

这就是为什么 Python 大神都在用 with 的原因——它能让你睡个安稳觉。

with的工作原理

with 语句背后是两个魔术方法:__enter__ 和 __exit__ 。

class FileManager:    def __init__(self, filename, mode):        self.filename = filename        self.mode = mode        self.file = Nonedef __enter__(self): print('准备打开文件...') self.file = open(self.filename, self.mode) return self.file # 这个返回值会赋给 as 后面的变量def __exit__(self, exc_type, exc_val, exc_tb): print('准备关闭文件...') if self.file: self.file.close()# 如果返回True,异常会被忽略# 如果返回False或None,异常会继续传播return False# 使用方式with FileManager('test.txt', 'w') as f: f.write('Hello World') # 这里就算抛异常,__exit__也会被调用

你可以把 with 想象成一个超级靠谱的管家:

  1. 你要进门前,管家提前帮你开门( __enter__ )
  2. 你在屋里随便折腾,管家在门口等着
  3. 你要出门时,管家帮你关门( __exit__ )
  4. 就算你在屋里摔倒了,管家也会先扶你起来,再帮你关门
实战场景:什么时候用with? 1. 文件操作(最常见)

# 读取大文件,不用担心忘记关闭with open('big_data.csv', 'r') as f: for line in f: process_line(line) # 就算这里内存溢出,文件也会关闭
2. 数据库连接

import sqlite3def update_user_money(user_id, amount): with sqlite3.connect('app.db') as conn: cursor = conn.cursor() cursor.execute('UPDATE users SET money = money + ? WHERE id = ?', (amount, user_id)) # 自动提交和关闭,就算这里抛异常也不会锁死数据库
3. 线程锁

import threadinglock = threading.Lock()def critical_section(): with lock: # 临界区代码,同时只能一个线程访问shared_resource += 1 # 就算这里抛异常,锁也会被释放,不会死锁
4. 网络请求

import requestsdef download_data(): with requests.Session() as session: session.auth = ('user', 'pass') response = session.get('https://api.example.com/data') # 连接池自动管理,不用担心资源泄漏
自定义上下文管理器

有时候你想创建自己的"自动管家",很简单:

from contextlib import contextmanager@contextmanager def timer(name): import time start = time.time() print(f'{name} 开始执行...') try: yield # 这里是 with 块中的代码finally: end = time.time() print(f'{name} 执行完毕,耗时:{end - start:.2f}秒')# 使用方式with timer('数据处理'): time.sleep(2) # 模拟耗时操作# 这里会自动计算并打印执行时间
踩坑指南 1. __exit__的返回值陷阱

class BadContext:    def __enter__(self):        print('进入')        return selfdef __exit__(self, exc_type, exc_val, exc_tb): print('退出') return True # 这行是陷阱!with BadContext(): 1 / 0 # 这个异常会被"吃掉"!print('程序继续运行,你都不知道出过异常!')

切记: 除非你真的知道自己在做什么,否则 __exit__ 应该返回 False 或 None 。

2. 异常信息丢失

def debug_context():    try:        with some_context():            risky_operation()    except Exception as e:        # 这里的e可能是上下文管理器抛出的异常# 而不是你真正想捕获的异常logger.error(f'出错了: {e}')
3. 嵌套with的性能

# ❌ 这样写性能不好with open('file1.txt') as f1: with open('file2.txt') as f2: with open('file3.txt') as f3: process_files(f1, f2, f3)# ✅ 推荐写法with open('file1.txt') as f1, \ open('file2.txt') as f2, \ open('file3.txt') as f3: process_files(f1, f2, f3)
进阶技巧 C 1. 使用contextlib.suppress

from contextlib import suppress# 有时候你就是想忽略某些异常with suppress(FileNotFoundError): os.remove('temp_file.txt') # 文件不存在也没关系
C 2. 使用contextlib.nullcontext

from contextlib import nullcontext# 有时候你条件性地需要上下文管理器context_manager = lock if use_lock else nullcontext()with context_manager: shared_operation()
总结

记住一句话:涉及资源的获取和释放,就考虑用 with 语句。

  • 文件操作?用with
  • 数据库连接?用with
  • 网络请求?用with
  • 线程锁?用with
  • 临时目录?用with

with 不是语法糖,是你的保险单。

下次再看到 open() 后面没有 with ,你就知道该说什么了:

"兄弟,你这代码能跑,但是我建议你买个保险..."

--- 你在项目里遇到过哪些资源泄漏的坑?评论区聊聊,看看谁的故事更惨!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

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.

相关推荐
热点推荐
101岁余宝珠:相貌普通击败正房,独占百亿资产,抽烟喝酒霸气足

101岁余宝珠:相貌普通击败正房,独占百亿资产,抽烟喝酒霸气足

照见古今
2026-01-09 19:08:21
“大尺度”新年挂历火了!活菩萨椰树怂了

“大尺度”新年挂历火了!活菩萨椰树怂了

李东阳朋友圈
2026-01-09 20:01:49
放弃美籍恢复中国籍,为办理税务需要,“中国刻蚀机之父”套现近1亿

放弃美籍恢复中国籍,为办理税务需要,“中国刻蚀机之父”套现近1亿

观察者网
2026-01-10 08:12:04
中国第二大内流河“原地复活”,曾经干到河床露底,如今又有水了

中国第二大内流河“原地复活”,曾经干到河床露底,如今又有水了

墨兰史书
2026-01-10 07:35:03
离谱!曝新科金球奖先生索要4.9亿元年薪 巴黎傻了:姆巴佩2.0?

离谱!曝新科金球奖先生索要4.9亿元年薪 巴黎傻了:姆巴佩2.0?

风过乡
2026-01-10 08:33:55
中韩为何没有发表联合声明,访华回国后的李在明,要心里有数

中韩为何没有发表联合声明,访华回国后的李在明,要心里有数

钦点历史
2026-01-09 15:24:57
给我跪下,你给我跪下!

给我跪下,你给我跪下!

布衣乱弹
2026-01-09 19:32:23
退出国家队,赴德国打球后离婚,如今已过去24年,丁松现状如何?

退出国家队,赴德国打球后离婚,如今已过去24年,丁松现状如何?

比利
2026-01-09 12:18:11
中国“万星计划”启动:2028年发射7600颗卫星,民营火箭引领手机直连时代!

中国“万星计划”启动:2028年发射7600颗卫星,民营火箭引领手机直连时代!

Thurman在昆明
2026-01-10 05:53:23
阿根廷大逆袭!米莱执政两年,通胀暴跌,经济增速扭负为正!

阿根廷大逆袭!米莱执政两年,通胀暴跌,经济增速扭负为正!

百态人间
2026-01-07 16:41:49
河南一男孩校内死亡后续:官方通报,知情人曝细节,校方恐担责!

河南一男孩校内死亡后续:官方通报,知情人曝细节,校方恐担责!

有范又有料
2026-01-10 09:31:25
73年毛主席接见韩先楚,闲聊时主席:你和许世友对我还是有感情的

73年毛主席接见韩先楚,闲聊时主席:你和许世友对我还是有感情的

谈古论今历史有道
2026-01-10 14:45:03
官媒主动下场,53岁孟晚舟再掀天花板,让任正非与整个商界沉默了

官媒主动下场,53岁孟晚舟再掀天花板,让任正非与整个商界沉默了

牛牛叨史
2026-01-07 13:34:04
天安门原升旗手张自轩结婚,岳父豪送奥迪A6,新娘身份不一般

天安门原升旗手张自轩结婚,岳父豪送奥迪A6,新娘身份不一般

八斗小先生
2026-01-08 18:19:01
伊朗巨变前夜

伊朗巨变前夜

凤眼论
2026-01-08 10:31:08
燃油车大败!12月SUV销量完整排名:Model Y断层领先,博越L第18

燃油车大败!12月SUV销量完整排名:Model Y断层领先,博越L第18

小怪吃美食
2026-01-10 09:16:33
江苏企退人员,12月过渡性养老金已增700元,2026年再增300元吗?

江苏企退人员,12月过渡性养老金已增700元,2026年再增300元吗?

八斗小先生
2026-01-09 10:57:25
刚来就想走?上海海港新外援:踢中超是为积累经验,盼将来回日本

刚来就想走?上海海港新外援:踢中超是为积累经验,盼将来回日本

国足风云
2026-01-10 07:59:58
致命失误吞里程悲!41岁詹皇末节13+5竭尽全力 美媒晒数据证伟大

致命失误吞里程悲!41岁詹皇末节13+5竭尽全力 美媒晒数据证伟大

颜小白的篮球梦
2026-01-10 13:54:48
重新定义永久中立国,瑞士冻结马杜罗资产,也是在砸美元霸权招牌

重新定义永久中立国,瑞士冻结马杜罗资产,也是在砸美元霸权招牌

闫树军论评
2026-01-10 15:20:04
2026-01-10 15:56:49
我不叫阿哏
我不叫阿哏
分享有趣、有用的故事!
243文章数 6237关注度
往期回顾 全部

科技要闻

传DeepSeek准备第二次震惊全世界

头条要闻

特朗普为何如此想要格陵兰岛 美联社用同个词解释3次

头条要闻

特朗普为何如此想要格陵兰岛 美联社用同个词解释3次

体育要闻

怒摔水瓶!杜兰特30+12 难阻火箭遭双杀

娱乐要闻

赵樱子称和蒋毅试婚三天:像试面膜

财经要闻

投资必看!瑞银李萌给出3大核心配置建议

汽车要闻

宝马25年全球销量246.3万台 中国仍是第一大市场

态度原创

时尚
亲子
本地
健康
家居

专栏 | 做“主语”的体验

亲子要闻

幼儿园元旦晚会 男子看见落单的,小男孩一脸失落主动将其抱起

本地新闻

云游内蒙|“包”你再来?一座在硬核里酿出诗意的城

这些新疗法,让化疗不再那么痛苦

家居要闻

木色留白 演绎现代自由

无障碍浏览 进入关怀版