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的Django框架中的项目进行单元测试的方法
Apr 11 Python
Python3中详解fabfile的编写
Jun 24 Python
Python wxpython模块响应鼠标拖动事件操作示例
Aug 23 Python
解决PyCharm同目录下导入模块会报错的问题
Oct 13 Python
Python实现 PS 图像调整中的亮度调整
Jun 28 Python
让Python脚本暂停执行的几种方法(小结)
Jul 11 Python
pycharm 2019 最新激活方式(pycharm破解、激活)
Sep 22 Python
python绘制玫瑰的实现代码
Mar 02 Python
python dict如何定义
Sep 02 Python
如何基于Django实现上下文章跳转
Sep 16 Python
mac系统下安装pycharm、永久激活、中文汉化详细教程
Nov 24 Python
Python爬虫进阶之爬取某视频并下载的实现
Dec 08 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
当海贼王变成JOJO风
2020/03/02 日漫
[原创]PHP中通过ADODB库实现调用Access数据库之修正版本
2006/12/31 PHP
php获取网页里所有图片并存入数组的方法
2015/04/06 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
2020/02/27 PHP
JS中字符问题(二进制/十进制/十六进制及ASCII码之间的转换)
2008/11/03 Javascript
异步javascript的原理和实现技巧介绍
2012/11/08 Javascript
javascript实现按回车键切换焦点
2015/02/09 Javascript
js实现的Easy Tabs选项卡用法实例
2015/09/06 Javascript
javascript类型系统 Window对象学习笔记
2016/01/07 Javascript
jquery.form.js框架实现文件上传功能案例解析(springmvc)
2016/05/26 Javascript
详解js的事件代理(委托)
2016/12/22 Javascript
javascript history对象详解
2017/02/09 Javascript
前端自动化开发之Node.js的环境搭建教程
2017/04/01 Javascript
Node.js+Express+MySql实现用户登录注册功能
2017/07/10 Javascript
详解vuex之store拆分即多模块状态管理(modules)篇
2018/11/13 Javascript
JS遍历JSON数组及获取JSON数组长度操作示例【测试可用】
2018/12/12 Javascript
微信小程序开发中var that =this的用法详解
2020/01/18 Javascript
JPype实现在python中调用JAVA的实例
2017/07/19 Python
Python 多核并行计算的示例代码
2017/11/07 Python
python3.5+tesseract+adb实现西瓜视频或头脑王者辅助答题
2018/01/17 Python
matplotlib作图添加表格实例代码
2018/01/23 Python
python文件绝对路径写法介绍(windows)
2019/12/25 Python
python数据预处理 :样本分布不均的解决(过采样和欠采样)
2020/02/29 Python
scrapy爬虫:scrapy.FormRequest中formdata参数详解
2020/04/30 Python
python如何处理程序无法打开
2020/06/16 Python
python中如何写类
2020/06/29 Python
html5 canvas绘制矩形和圆形的实例代码
2016/06/16 HTML / CSS
html5是什么_动力节点Java学院整理
2017/07/07 HTML / CSS
澳大利亚墨水站Ink Station:墨水和碳粉打印机墨盒
2019/03/24 全球购物
Penhaligon’s英国官网:成立于1870年的英国香水制造商
2021/02/18 全球购物
学校就业推荐信范文
2014/05/19 职场文书
离婚协议书范文2014
2014/10/16 职场文书
综合实践活动报告
2015/02/05 职场文书
2015年小学美术工作总结
2015/05/25 职场文书
励志语录:时光飞逝,请学会珍惜所有的人和事
2020/01/16 职场文书
关于redisson缓存序列化几枚大坑说明
2021/08/04 Redis