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抓取百度查询结果的方法
Jul 08 Python
Python找出最小的K个数实例代码
Jan 04 Python
基于DataFrame改变列类型的方法
Jul 25 Python
Python3.7 dataclass使用指南小结
Feb 22 Python
详解python中递归函数
Apr 16 Python
Python从函数参数类型引出元组实例分析
May 28 Python
python并发编程多进程 互斥锁原理解析
Aug 20 Python
如何分离django中的媒体、静态文件和网页
Nov 12 Python
django 中使用DateTime常用的时间查询方式
Dec 03 Python
python 字典访问的三种方法小结
Dec 05 Python
python argparse模块通过后台传递参数实例
Apr 20 Python
Python 如何反方向迭代一个序列
Jul 28 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中遇到BOM、编码导致json_decode函数无法解析问题
2014/07/02 PHP
ThinkPHP中limit()使用方法详解
2016/04/19 PHP
项目中应用Redis+Php的场景
2016/05/22 PHP
php获取POST数据的三种方法实例详解
2016/12/20 PHP
php修改数组键名的方法示例
2017/04/15 PHP
php curl上传、下载、https登陆实现代码
2017/07/23 PHP
利用Laravel生成Gravatar头像地址的优雅方法
2017/12/30 PHP
PHP接入微信H5支付的方法示例
2019/10/28 PHP
js实现在页面上弹出蒙板技巧简单实用
2013/04/16 Javascript
js实现右下角可关闭最小化div(可用于展示推荐内容)
2013/06/24 Javascript
JQuery的ON()方法支持的所有事件罗列
2015/02/28 Javascript
Jquery插件之Fancybox丰富的弹出层效果附源码下载
2015/12/02 Javascript
快速掌握Node.js中setTimeout和setInterval的使用方法
2016/03/21 Javascript
jQuery 实现ajax传入参数含有特殊字符的方法总结
2016/10/17 Javascript
基于JavaScript实现熔岩灯效果导航菜单
2017/01/04 Javascript
Vue.js实现表格动态增加删除的方法(附源码下载)
2017/01/20 Javascript
Bootstrap实现的标签页内容切换显示效果示例
2017/05/25 Javascript
深入理解Nodejs Global 模块
2017/06/03 NodeJs
详解使用webpack打包编写一个vue-toast插件
2017/11/08 Javascript
详解一个基于套接字实现长连接的express
2019/03/28 Javascript
js实现二级联动简单实例
2020/01/11 Javascript
原生JavaScript实现留言板
2021/01/10 Javascript
[01:02:00]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第三场 1月24日
2021/03/11 DOTA
你应该知道的python列表去重方法
2017/01/17 Python
Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例
2018/07/27 Python
Pycharm 实现下一个文件引用另外一个文件的方法
2019/01/17 Python
Python递归函数特点及原理解析
2020/03/04 Python
python unichr函数知识点总结
2020/12/16 Python
伦敦鲜花递送:Flower Station
2021/02/03 全球购物
如何写一个Java类既可以用作applet也可以用作java应用
2016/01/18 面试题
应聘自荐书
2013/10/08 职场文书
教学评估实施方案
2014/03/16 职场文书
表扬稿格式范文
2015/01/16 职场文书
经典人生语录分享:不畏将来,不念过去,笑对当下
2019/12/12 职场文书
Idea连接MySQL数据库出现中文乱码的问题
2021/04/14 MySQL
解决ubuntu安装软件时,status-code=409报错的问题
2022/12/24 Servers