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


Posted in Python onAugust 07, 2020

问题

你想自己去实现一个新的上下文管理器,以便使用with语句。

解决方案

实现一个新的上下文管理器的最简单的方法就是使用 contexlib 模块中的 @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]
>>>

讨论

通常情况下,如果要写一个上下文管理器,你需要定义一个类,里面包含一个 __enter__() 和一个 __exit__() 方法,如下所示:

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 相关文章推荐
Python 文件读写操作实例详解
Mar 12 Python
Python工程师面试必备25条知识点
Jan 17 Python
利用python实现微信头像加红色数字功能
Mar 26 Python
Python中list查询及所需时间计算操作示例
Jun 21 Python
Python统计python文件中代码,注释及空白对应的行数示例【测试可用】
Jul 25 Python
python 顺时针打印矩阵的超简洁代码
Nov 14 Python
Python面向对象程序设计OOP深入分析【构造函数,组合类,工具类等】
Jan 05 Python
关于numpy中eye和identity的区别详解
Nov 29 Python
python二分法查找算法实现方法【递归与非递归】
Dec 06 Python
使用Python实现Wake On Lan远程开机功能
Jan 22 Python
解决reload(sys)后print失效的问题
Apr 25 Python
python 如何快速复制序列
Sep 07 Python
Python 读取位于包中的数据文件
Aug 07 #Python
Python如何绘制日历图和热力图
Aug 07 #Python
Pycharm2020.1安装无法启动问题即设置中文插件的方法
Aug 07 #Python
手把手教你如何用Pycharm2020.1.1配置远程连接的详细步骤
Aug 07 #Python
Pycharm2020.1安装中文语言插件的详细教程(不需要汉化)
Aug 07 #Python
Pycharm 2020.1 版配置优化的详细教程
Aug 07 #Python
解决阿里云邮件发送不能使用25端口问题
Aug 07 #Python
You might like
JavaScript创建命名空间的5种写法
2014/06/24 PHP
javascript IFrame 强制刷新代码
2009/07/23 Javascript
jquery中获取元素的几种方式小结
2011/07/05 Javascript
模拟select的代码
2011/10/19 Javascript
javascript全局变量封装模块实现代码
2012/11/28 Javascript
JavaScript 和 Java 的区别浅析
2013/07/31 Javascript
JS格式化数字金额用逗号隔开保留两位小数
2013/10/18 Javascript
解析img图片没找到onerror事件 Stack overflow at line: 0
2013/12/23 Javascript
从零学JS之你需要了解的几本书
2014/05/19 Javascript
JavaScript中模拟实现jsonp
2015/06/19 Javascript
JavaScript用select实现日期控件
2015/07/17 Javascript
javascript中不易分清的slice,splice和split三个函数
2016/03/29 Javascript
Jquery实现$.fn.extend和$.extend函数
2016/04/14 Javascript
微信小程序 获取相册照片实例详解
2016/11/16 Javascript
JavaScript实现简单的星星评分效果
2017/05/18 Javascript
vue2利用Bus.js如何实现非父子组件通信详解
2017/08/25 Javascript
Bootstrap的aria-label和aria-labelledby属性实例详解
2018/11/02 Javascript
vue项目打包上传github并制作预览链接(pages)
2019/04/19 Javascript
javascript/jquery实现点击触发事件的方法分析
2019/11/11 jQuery
Python天气预报采集器实现代码(网页爬虫)
2012/10/07 Python
学习python的几条建议分享
2013/02/10 Python
python实现数通设备端口监控示例
2014/04/02 Python
Python2.7下安装Scrapy框架步骤教程
2017/12/22 Python
python kmeans聚类简单介绍和实现代码
2018/02/23 Python
python日期相关操作实例小结
2019/06/24 Python
python批量处理txt文件的实例代码
2020/01/13 Python
美国受欢迎的女性牛仔裤品牌:DL1961
2016/11/12 全球购物
欧洲领先的技术商店:eibmarkt.com
2019/05/10 全球购物
乔丹名人堂演讲稿
2014/05/24 职场文书
年终考核实施方案
2014/05/26 职场文书
党员干部反四风民主生活会对照检查材料思想汇报
2014/10/12 职场文书
鸟的天堂导游词
2015/01/31 职场文书
给老师的保证书怎么写
2015/05/09 职场文书
大学运动会加油稿
2015/07/22 职场文书
Smart 2 车辆代号 HC11 全新谍照曝光
2022/04/21 数码科技
Python中tqdm的使用和例子
2022/09/23 Python