Python实现上下文管理器的方法

向北走
向北走
发布时间:2026-10-14 | 3人浏览过
原创

本文介绍Python中实现上下文管理器的两种主要方式:使用contextlib模块的@contextmanager装饰器简化函数实现,以及通过定义包含__enter__()和__exit__()方法的类来实现复杂逻辑。文章通过代码计时和列表事务两个实例,详细演示了yield语句在上下文管理中的作用及异常处理机制,帮助开发者掌握with语句的高级应用。

Python上下文管理器实现概述

问题

开发者希望自定义实现一个新的上下文管理器,从而能够在代码中使用with语句来管理资源或执行特定操作。

使用@contextmanager简化实现

解决方案

实现新上下文管理器最简便的途径是利用contextlib模块提供的@contextmanager装饰器。以下示例展示了一个用于统计代码块执行时间的上下文管理器实现:


import time
from contextlib import contextmanager

@contextmanager
def timethis(label):
  start = time.time()
  try:
    yield
  finally:
    end = time.time()
    print('{}: {}'.format(label, end - start))

# Example use
with timethis('counting'):
  n = 10000000
  while n > 0:
    n -= 1

在timethis() 函数内部,位于yield语句之前的代码逻辑将在上下文管理器进入时作为__enter__() 方法执行;而位于yield 语句之后的代码则作为 __exit__() 方法执行。若在执行过程中发生异常,该异常将被抛出至yield语句处进行处理。

接下来展示一个更为复杂的上下文管理器示例,该示例实现了针对列表对象的事务性操作:


@contextmanager
def list_transaction(orig_list):
  working = list(orig_list)
  yield working
  orig_list[:] = working

此代码确保了对列表的任何修改仅在所有代码执行完毕且未发生异常时才正式生效。具体演示如下:


>>> items = [1, 2, 3]
>>> with list_transaction(items) as working:
...   working.append(4)
...   working.append(5)
...
>>> items
[1, 2, 3, 4, 5]
>>> with list_transaction(items) as working:
...   working.append(6)
...   working.append(7)
...   raise RuntimeError('oops')
...
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: oops
>>> items
[1, 2, 3, 4, 5]
>>>

基于类的上下文管理器实现

讨论

一般而言,编写上下文管理器需要定义一个类,并实现和两个方法,具体结构如下:


import time

class timethis:
  def __init__(self, label):
    self.label = label

  def __enter__(self):
    self.start = time.time()

  def __exit__(self, exc_ty, exc_val, exc_tb):
    end = time.time()
    print('{}: {}'.format(self.label, end - self.start))

虽然这种基于类的实现方式并不复杂,但相较于编写一个带有@contextmanager 装饰器的简单函数而言,其代码量稍显繁琐。

@contextmanager装饰器适用于编写自包含的上下文管理函数。如果存在如文件、网络连接或锁等对象,需要支持with 语句,则必须单独实现 __enter__() 和__exit__() 方法以处理资源的获取与释放。

以上即为Python实现上下文管理器的核心内容,更多关于Python实现上下文管理器的详细信息,建议关注本站发布的其他相关文章。

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表