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递归计算N!的方法
May 05 Python
Python的语言类型(详解)
Jun 24 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
Aug 18 Python
Python3导入自定义模块的三种方法详解
Apr 13 Python
tensorflow 打印内存中的变量方法
Jul 30 Python
在python 不同时区之间的差值与转换方法
Jan 14 Python
在Python中使用Neo4j的方法
Mar 14 Python
Django模型序列化返回自然主键值示例代码
Jun 12 Python
python中break、continue 、exit() 、pass终止循环的区别详解
Jul 08 Python
Flask框架学习笔记之表单基础介绍与表单提交方式
Aug 12 Python
详解Python在使用JSON时需要注意的编码问题
Dec 06 Python
python实现MD5进行文件去重的示例代码
Jul 09 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
php微信支付接口开发程序
2016/08/02 PHP
php从数据库中获取数据用ajax传送到前台的方法
2018/08/20 PHP
JS维吉尼亚密码算法实现代码
2010/11/09 Javascript
javascript与webservice的通信实现代码
2010/12/25 Javascript
JQuery each打印JS对象的方法
2013/11/13 Javascript
JS使用getComputedStyle()方法获取CSS属性值
2014/04/23 Javascript
iframe里的页面禁止右键事件的方法
2014/06/10 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
通过node-mysql搭建Windows+Node.js+MySQL环境的教程
2016/03/01 Javascript
jQuery简单实现仿京东分类导航层效果
2016/06/07 Javascript
JS实现的简易拖放效果示例
2016/12/29 Javascript
基于vue+ bootstrap实现图片上传图片展示功能
2017/05/17 Javascript
如何编写一个完整的Angular4 FormText 组件
2017/11/18 Javascript
vue 项目如何引入微信sdk接口的方法
2017/12/18 Javascript
TypeScript基础入门教程之三重斜线指令详解
2018/10/22 Javascript
vue2 拖动排序 vuedraggable组件的实现
2019/08/08 Javascript
解决layui的radio属性或别的属性没显示出来的问题
2019/09/26 Javascript
JavaScript使用百度ECharts插件绘制饼图操作示例
2019/11/26 Javascript
微信小程序开发(二):页面跳转并传参操作示例
2020/06/01 Javascript
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Python中用max()方法求最大值的介绍
2015/05/15 Python
初学python的操作难点总结(新手必看篇)
2017/08/03 Python
Python协程的用法和例子详解
2017/09/09 Python
python实现批量按比例缩放图片效果
2018/03/30 Python
Python使用add_subplot与subplot画子图操作示例
2018/06/01 Python
解决PyCharm的Python.exe已经停止工作的问题
2018/11/29 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
css3动画 小球滚动 js控制动画暂停
2019/11/29 HTML / CSS
Camille Jewelry官网:现代女性时尚首饰
2019/07/07 全球购物
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
三年级音乐教学反思
2014/01/28 职场文书
全国文明单位申报材料
2014/05/31 职场文书
工作证明范本(2篇)
2014/09/14 职场文书
2014年团委工作总结
2014/11/13 职场文书
2014年销售部工作总结
2014/12/01 职场文书
SpringBoot2零基础到精通之异常处理与web原生组件注入
2022/03/22 Java/Android