Python with语句与上下文管理器详解

闻溪
闻溪
发布时间:2026-10-13 | 6人浏览过
原创

本文深入解析Python中with语句的工作原理及其在资源管理中的应用。通过对比传统try-finally代码,阐述with语句如何自动执行__enter__和__exit__方法以释放资源。同时介绍利用contextlib模块和装饰器自定义上下文管理器的方法,帮助开发者编写更简洁、安全的代码。

Python with语句基础与资源管理

Python中的with语句主要用于资源访问场景,确保无论处理过程中是否发生错误或异常,都会执行规定的__exit__(清理)操作,从而释放被访问的资源。常见的应用场景包括文件读写后自动关闭、线程中锁的自动获取与释放等。

理解with语句涉及几个核心概念:上下文管理协议、上下文管理器、运行时上下文、上下文表达式以及处理资源的代码段。

with语句的应用场景

with语句的应用场景

编程中存在大量配套使用的操作,这类流程可称为计算过程。Python语言为此专门设计了with语句结构。文件处理便是此类计算过程的典型代表。

使用with语句前后的代码对比

使用with语句前后对比

在未使用with语句之前,打开文件的常规写法如下:


try:
 # 1. [进入]
 f = open('a.txt', 'r', encoding="utf-8")
 # 2. [执行]
 print(f.read())
finally:
 if f:
  # 3. [退出]
  f.close()

Python操作文件通常遵循以下三个步骤:

1. [进入]以只读方式打开文件

若文件不存在,open()函数将抛出IOError错误,并提供错误码及详细信息提示文件缺失。

2. [执行]读取文件内容

若文件打开成功,调用read()方法可一次性读取全部内容。Python将内容加载至内存,并以str对象形式表示。

3. [退出]关闭打开的文件

文件使用完毕后必须关闭,因为文件对象会占用操作系统资源,且操作系统同时能打开的文件数量有限。

思考:为何关闭文件操作必须放在finally语句中?

由于文件读写时可能产生IOError,一旦出错,后续的f.close()便不会执行。因此,为确保无论是否出错都能正确关闭文件,可使用try ... finally结构来实现。

发现共性:

我们发现这类过程化语句具有共性:在进入一个片段前时必须执行某种操作,处理工作后后需要执行结束操作。例如上述代码:


finally:
 if f:
  f.close()

即可进行封装处理。

使用with语句后,打开文件的方式变为:


with open("a.txt", "r", encoding="utf-8") as f:
 print(f.read())

该with语句与前述try ... finally结构功能一致,但代码更为简洁,且无需显式调用f.close()方法。

with语句的执行原理与上下文管理器

with语句的执行原理

从解释器角度理解with语句的执行流程。

with语句的基本形式为:


with 表达式 as 变量:
 语句块

此类代码称为一个上下文(context)。执行with语句时,解释器先计算表达式的值,该值(对象)为上下文管理器,并假设该对象拥有如下类构造方法:


def __enter__():
  # 描述进入上下文的动作
  pass

 def __exit__():
  # 描述退出上下文的动作
  pass

with语句在获取上下文管理器对象后,自动执行进入方法,并将返回值赋值给as后的变量,随后执行语句块。退出上下文前,自动执行对象的退出方法。

Python系统及标准库中部分类型已定义这对操作,可直接用于with语句。例如文件对象直接支持此对操作,因此可置于with语句头部。

若你有类似的计算过程需抽取,可自定义类并包含进入与退出方法。

使用contextlib自定义上下文管理器

自定义open函数

实际实现中发现,使用装饰器和生成器即可很好地解决该问题,无需通过类构造方法实现:


import contextlib # 引入上下文管理包

@contextlib.contextmanager # 给函数引入装饰器
def myopen(dir, mode):
 print("开始")
 f = open(dir, mode, encoding='utf-8')
 try: # 上文
  yield f
 finally: # 下文
  print("结束")
  f.close()

with myopen("a.txt", 'r') as fobj: # 把try中的yield中的f赋值给fobj
 # with会将with后面的函数中的yield赋值给fobj
 for i in fobj:
  print(i)
  # 等待上面的循环结束后,才最终执行finally的代码,所以这就是上下文管理

输出结果如下:


开始
hello,我是a.txt的第1行文字。
结束

with语句总结与最佳实践

总结

文件读写、使用pickle包进行数据存储与恢复等操作,均非常适合使用with语句。

pickle包的使用案例:


try:
 with open("phone.pickle", "wb") as outf:
  pickle.dump("13193388105", outf)
except:
 print("file have errow.")


try:
 with open("phone.pickle", "rb") as outf:
  data = pickle.load(outf)
  print(type(data))
  print(data)
except:
 print("file have errow.")

总结使用with语句的优点:

  • 采用with语句的代码更加简洁。
  • 避免因忘记调用f.close()而引发的错误。
  • 若对象操作包含进入与退出过程,可将其抽取并实现自动化执行。

总结

以上介绍了Python with语句及过程抽取思想,希望能对大家有所帮助。如有任何疑问,请留言,小编会及时回复。感谢大家对本站的支持!若觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表