当前位置:首页>python>别再手动读写文件了,Python上下文管理器了解一下

别再手动读写文件了,Python上下文管理器了解一下

  • 2026-08-28 10:09:12
别再手动读写文件了,Python上下文管理器了解一下

每天写文件读文件,用 open 函数打开,用完还得 close。少写一次 close ,文件句柄就漏了。漏多了,程序就报错,报错还不好查。

有人用 try finally 包着,代码写了一大堆,看着就累。还有人干脆不关,等垃圾回收,那是赌运气,运气不好线上就崩。

上下文管理器就是干这个的。with open('file.txt', 'r') as f: 这一行,文件打开,代码块跑完,文件自己关。不用你操心。

with 语句的本质,是让对象管理自己的生命周期。你只管用,它管收尾。这跟现实里的租赁一样,签个合同,到期自动退房,不用你半夜爬起来锁门。

不光文件能用。数据库连接,网络 socket ,线程锁,都适用。场景不同,道理一个样。

写一个自己的上下文管理器,也不难。类里实现两个方法,__enter__ 负责准备资源,__exit__ 负责清理资源。比如一个数据库操作,enter 里建立连接,exit 里提交或回滚,再断开连接。用 with 包起来,事务边界清清楚楚。

class Database: 

   def __enter__(self):

       self.conn = create_connection()

       return self.conn

   def __exit__(self, exc_type, exc_val, exc_tb):

       if exc_type:

           self.conn.rollback()

       else:

           self.conn.commit()

       self.conn.close()

代码里的 exc_type 那几个参数,就是用来处理异常的。代码块里抛了异常,exit 会收到异常类型和值。你可以做清理,也可以拦下来不往外抛,全看业务怎么定。

还有一个更省事的写法,用 @contextmanager 装饰器。把 yield 放在中间,yield 之前是 enter 的逻辑,yield 之后是 exit 的逻辑。代码更短,读起来更直白。

from contextlib import contextmanager 

@contextmanager

def temp_file(name):

   f = open(name, 'w')

   try:

       yield f

   finally:

       f.close()

用的时候,with temp_file('test.txt') as f: 一行调用。里面写错了,最后一行 close 还是会执行。这个 try finally 是装饰器帮你补上的,你只要写业务,不必写收尾。

很多人不习惯用 with ,是觉得多一层缩进,麻烦。但为了不缩进,付出的代价是忘记关闭资源的隐患。线上跑着跑着,报 “Too many open files” ,查半天,最后发现是某处文件没关。那种坑,踩一次就够。

还有一种场景,就是临时改环境变量,或者临时改当前目录。用上下文管理器,进出都自动还原,不会影响其他代码。

@contextmanager 

def set_env(key, value):

   old = os.environ.get(key)

   os.environ[key] = value

   try:

       yield

   finally:

       if old is None:

           del os.environ[key]

       else:

           os.environ[key] = old

这个模式在写测试的时候特别有用。测试要临时改某个配置,跑完用例,配置要还原。手写 try finally 很容易漏,用 with 包一层,永远不会漏。

上下文管理器的核心价值,就是把一对动作绑定在一起,保证一前一后必然执行。不用你记,不会忘,也不怕异常打断流程。

下次写代码,凡是遇到“打开什么,用完必须关”的场景,先想想能不能用 with 。文件、网络、锁、临时环境,都用得上。用多了,你会觉得以前手动 close 的日子,纯粹是给自己找麻烦。

最新文章

随机文章