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 相关文章推荐
Python3的urllib.parse常用函数小结(urlencode,quote,quote_plus,unquote,unquote_plus等)
Sep 18 Python
Django基础之Model操作步骤(介绍)
May 27 Python
python 字符串和整数的转换方法
Jun 25 Python
python计算列表内各元素的个数实例
Jun 29 Python
解决nohup执行python程序log文件写入不及时的问题
Jan 14 Python
Python基本socket通信控制操作示例
Jan 30 Python
Python文件读写常见用法总结
Feb 22 Python
Django rstful登陆认证并检查session是否过期代码实例
Aug 13 Python
pytorch实现seq2seq时对loss进行mask的方式
Feb 18 Python
python保留格式汇总各部门excel内容的实现思路
Jun 01 Python
tensorflow dataset.shuffle、dataset.batch、dataset.repeat顺序区别详解
Jun 03 Python
python实现杨辉三角的几种方法代码实例
Mar 02 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
让这部DC动画新作刷新你的认知
2020/03/03 欧美动漫
php中目录,文件操作详谈
2007/03/19 PHP
php 用checkbox一次性删除多条记录的方法
2010/02/23 PHP
PHP array_multisort() 函数的深入解析
2013/06/20 PHP
php生成图片验证码
2015/06/09 PHP
thinkphp框架类库扩展操作示例
2019/11/26 PHP
PHP 范围解析操作符(::)用法分析【访问静态成员和类常量】
2020/04/14 PHP
Jquery 基础学习笔记
2009/05/29 Javascript
web 页面分页打印的实现
2009/06/22 Javascript
工作需要写的一个js拖拽组件
2011/07/28 Javascript
struts2+jquery组合验证注册用户是否存在
2014/04/30 Javascript
JQuery实现简单的图片滑动切换特效
2015/11/22 Javascript
详解JavaScript基于面向对象之继承实例
2015/12/16 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
2016/03/19 Javascript
关于前后端json数据的发送与接收详解
2017/07/30 Javascript
NodeJS设计模式总结【单例模式,适配器模式,装饰模式,观察者模式】
2017/09/06 NodeJs
vue实现前进刷新后退不刷新效果
2018/01/26 Javascript
vue.js移动数组位置,同时更新视图的方法
2018/03/08 Javascript
[03:43]2014DOTA2西雅图国际邀请赛 newbee战队巡礼
2014/07/07 DOTA
[01:30:54]《加油DOTA》 第三期
2014/08/18 DOTA
python 示例分享---逻辑推理编程解决八皇后
2014/07/20 Python
python实现红包裂变算法
2016/02/16 Python
使用Python读写及压缩和解压缩文件的示例
2016/07/08 Python
Python urls.py的三种配置写法实例详解
2017/04/28 Python
python字典的遍历3种方法详解
2019/08/10 Python
Python-openCV读RGB通道图实例
2020/01/17 Python
python实现PDF中表格转化为Excel的方法
2020/06/16 Python
思想品德自我鉴定
2013/10/12 职场文书
优秀求职自荐信怎样写
2013/12/18 职场文书
任命书模板
2014/06/04 职场文书
公务员四风问题对照检查材料整改措施
2014/09/26 职场文书
师德自我剖析材料范文
2014/10/06 职场文书
2014年城管个人工作总结
2014/12/08 职场文书
幼儿园科学课教学反思
2016/03/03 职场文书
SQL Server——索引+基于单表的数据插入与简单查询【1】
2021/04/05 SQL Server
Python中生成随机数据安全性、多功能性、用途和速度方面进行比较
2022/04/14 Python