Python with语句详解:自动资源管理与上下文协议

苏见山
苏见山
发布时间:2026-10-13| 4人浏览过
原创

本文深入解析Python中with语句的用法与原理。通过示例展示如何利用with自动关闭文件,并详细讲解上下文管理协议。重点介绍__enter__和__exit__方法的实现细节,包括异常处理机制及返回值处理,帮助用户掌握自定义类支持with语句管理资源的核心技巧。

Python with语句基础与文件管理

在Python编程中,资源管理至关重要。为了确保资源被正确释放,Python提供了with语句。使用with语句包裹打开的文件对象,系统会在代码块执行完毕后自动调用关闭操作,无需手动干预。

with语句的基本语法结构如下所示:


with context expression [as target(s)]:
  with 代码块

在此语法结构中,context_expression负责生成一个可自动管理的资源对象。

以下代码演示了如何使用with语句读取文件内容:


import codecs
# 使用with语句打开文件,该语句会负责关闭文件
with codecs.open("readlines_test.py", 'r', 'utf-8', buffering=True) as f:
  for line in f:
    print(line, end='')

同样,利用fileinput.input合并处理多个文件时,也可以借助with语句简化操作,具体代码如下:


import fileinput
# 使用with语句打开文件,该语句会负责关闭文件
with fileinput.input(files=('test.txt', 'info.txt')) as f:
  for line in f:
    print(line, end='')

上述两个示例均通过with语句管理资源,因此程序无需显式调用关闭文件的方法。

上下文管理协议与实现原理

with语句背后的实现机制并不复杂。关键在于被管理的资源必须是一个实现了上下文管理协议(context management protocol)的类,其实例被称为上下文管理器。要满足该协议,类必须定义以下两个核心方法:

  • context_manager.__enter__():进入上下文时自动调用的方法。它在with代码块执行前运行。若存在as子句,该方法的返回值将赋给as后的变量;该方法可返回多个值,此时as子句需用括号包裹以组成元组接收。
  • context_manager.__exit__(exc_type, exc_value, exc_traceback):退出上下文时自动调用的方法。它在with代码块执行后运行。若代码块正常结束,传入该方法的三个参数均为None;若因异常中止,则通过sys.exc_info获取的异常信息将作为参数传入。

由此可见,只要类实现了__enter__()和__exit__(exc_type, exc_value, exc_traceback)方法,即可使用with语句进行管理。通过__exit__方法的参数,可以判断代码块执行期间是否发生异常。

换句话说,前文示例中的文件对象和FileInput对象均实现了这两个方法,因此它们天然支持with语句的管理。

自定义上下文管理器示例

接下来,我们自定义一个实现上下文管理协议的类,并演示如何使用with语句对其进行管理:


class FkResource:
  def __init__(self, tag):
    self.tag = tag
    print('构造器,初始化资源: %s' % tag)
  # 定义__enter__方法,with体之前的执行的方法
  def __enter__(self):
    print('[__enter__ %s]: ' % self.tag)
    # 该返回值将作为as子句中变量的值
    return 'fkit' # 可以返回任意类型的值
  # 定义__exit__方法,with体之后的执行的方法
  def __exit__(self, exc_type, exc_value, exc_traceback):
    print('[__exit__ %s]: ' % self.tag)
    # exc_traceback为None,代表没有异常
    if exc_traceback is None:
      print('没有异常时关闭资源')
    else:
      print('遇到异常时关闭资源')
      return False  # 可以省略,默认返回None也被看做是False
with FkResource('孙悟空') as dr:
  print(dr)
  print('[with代码块] 没有异常')
print('------------------------------')
with FkResource('白骨精'):
  print('[with代码块] 异常之前的代码')
  raise Exception
  print('[with代码块] ~~~~~~~~异常之后的代码')

上述代码定义了一个FkResource类,其中包含__enter__()和__exit__()两个方法,因此该类的实例可以被with语句管理:

  • 当程序执行with代码块前,会先执行__enter__()方法,并将其返回值赋给as子句后的变量。
  • 当程序执行with代码块后,会执行__exit__()方法,通过该方法的参数可以判断代码块执行过程中是否出现异常。

程序两次使用with语句管理FkResource对象。第一次运行中,with代码块未出现异常;第二次运行中,代码块触发了异常。对比可见,两种情况下with语句对FkResource的管理存在差异,主要体现在__exit__()方法的执行逻辑上。

运行上述程序,得到的输出结果如下:


构造器,初始化资源: 孙悟空
[__enter__ 孙悟空]:
fkit
[with代码块] 没有异常
[__exit__ 孙悟空]:
没有异常时关闭资源
------------------------------
构造器,初始化资源: 白骨精
[__enter__ 白骨精]:
[with代码块] 异常之前的代码
[__exit__ 白骨精]:
遇到异常时关闭资源
Traceback (most recent call last):
 File "C:\Users\mengma\Desktop\1.py", line 26, in <module>
  raise Exception
Exception

从输出结果可以看出,无论with代码块是否发生异常,程序都会在进入代码块前自动执行__enter__()方法。此外,__enter__()方法的返回值会被赋给as子句后的变量,如输出信息①所示。

针对with代码块有异常和无异常两种情况,主要通过__exit__()方法的参数进行区分。程序可根据是否有异常执行不同的处理逻辑,如代码所示。

以上内容涵盖了Python with语句的核心用法与原理,希望能对读者的学习有所帮助。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。