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 re正则表达式模块(Regular Expression)
Jul 16 Python
研究Python的ORM框架中的SQLAlchemy库的映射关系
Apr 25 Python
Python编程中实现迭代器的一些技巧小结
Jun 21 Python
Django入门使用示例
Dec 12 Python
python实现简单遗传算法
Mar 19 Python
完美解决python中ndarray 默认用科学计数法显示的问题
Jul 14 Python
对python numpy.array插入一行或一列的方法详解
Jan 29 Python
django将网络中的图片,保存成model中的ImageField的实例
Aug 07 Python
python进阶之自定义可迭代的类
Aug 20 Python
Python3实现zip分卷压缩过程解析
Oct 09 Python
Python基于requests库爬取网站信息
Mar 02 Python
在jupyter notebook中调用.ipynb文件方式
Apr 14 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读取PDF内容配合Xpdf的使用
2012/11/24 PHP
PHP里8个鲜为人知的安全函数分析
2014/12/09 PHP
php读取和保存base64编码的图片内容
2017/04/22 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
2019/11/26 PHP
JavaScript与DropDownList 区别分析
2010/01/01 Javascript
JS中的public和private对象,即static修饰符
2012/01/18 Javascript
JQuery文字列表向上滚动的代码
2013/11/13 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
高性能JavaScript DOM编程(1)
2015/08/11 Javascript
Jquery轮播效果实现过程解析
2016/03/30 Javascript
JavaScript数组去重的几种方法效率测试
2016/10/23 Javascript
jquery-mobile基础属性与用法详解
2016/11/23 Javascript
浅谈AngularJS中使用$resource(已更新)
2017/09/14 Javascript
微信小程序单选radio及多选checkbox按钮用法示例
2019/04/30 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
Layui数据表格之单元格编辑方式
2019/10/26 Javascript
Echarts实现单条折线可拖拽效果
2019/12/19 Javascript
用js实现放大镜效果
2020/10/28 Javascript
Python中使用Inotify监控文件实例
2015/02/14 Python
探究Python的Tornado框架对子域名和泛域名的支持
2015/05/02 Python
python网络编程之数据传输UDP实例分析
2015/05/20 Python
python简单实现获取当前时间
2016/08/27 Python
Django实现快速分页的方法实例
2017/10/22 Python
Python父目录、子目录的相互调用方法
2019/02/16 Python
Python Gitlab Api 使用方法
2019/08/28 Python
详解Python 最短匹配模式
2020/07/29 Python
Linux常见面试题
2013/03/18 面试题
大学生旷课检讨书
2014/01/22 职场文书
网络技术专业推荐信
2014/02/20 职场文书
升国旗仪式主持词
2014/03/19 职场文书
医院节能减排方案
2014/06/13 职场文书
2015年艾滋病宣传活动总结
2015/03/27 职场文书
单独二胎证明
2015/06/24 职场文书
毕业班工作总结
2015/08/10 职场文书
2019年干货:自我鉴定
2019/03/25 职场文书
python内置进制转换函数的操作
2021/06/02 Python