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基础教程之popen函数操作其它程序的输入和输出示例
Feb 10 Python
Python中logging模块的用法实例
Sep 29 Python
Django中对数据查询结果进行排序的方法
Jul 17 Python
关于Python元祖,列表,字典,集合的比较
Jan 06 Python
Python之Scrapy爬虫框架安装及简单使用详解
Dec 22 Python
python实现决策树分类(2)
Aug 30 Python
Python全局变量与局部变量区别及用法分析
Sep 03 Python
python获取当前文件路径以及父文件路径的方法
Jul 10 Python
Python适配器模式代码实现解析
Aug 02 Python
python mqtt 客户端的实现代码实例
Sep 25 Python
详解selenium + chromedriver 被反爬的解决方法
Oct 28 Python
Python可变集合和不可变集合的构造方法大全
Dec 06 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
Yii2简单实现多语言配置的方法
2016/07/23 PHP
php mysql PDO 查询操作的实例详解
2017/09/23 PHP
YII框架实现自定义第三方扩展操作示例
2019/04/26 PHP
Javascript delete 引用类型对象
2013/11/01 Javascript
js实现简单锁屏功能实例
2015/05/27 Javascript
Javascript中call,apply,bind方法的详解与总结
2016/12/12 Javascript
bootstrap侧边栏圆点导航
2017/01/11 Javascript
JavaScript制作简易计算器(不用eval)
2017/02/05 Javascript
jQuery实现简单漂亮的Nav导航菜单效果
2017/03/29 jQuery
vue-cli如何快速构建vue项目
2017/04/26 Javascript
微信小程序 空白页重定向解决办法
2017/06/27 Javascript
使用JS中的Replace()方法遇到的问题小结
2017/10/20 Javascript
在 webpack 中使用 ECharts的实例详解
2018/02/05 Javascript
浅谈angularJs函数的使用方法(大小写转换,拷贝,扩充对象)
2018/10/08 Javascript
express.js中间件说明详解
2019/03/19 Javascript
详解key在Vue列表渲染时究竟起到了什么作用
2019/04/20 Javascript
微信小程序移动拖拽视图-movable-view实例详解
2019/08/17 Javascript
layer提示框添加多个按钮选择的实例
2019/09/12 Javascript
jQuery事件模型默认行为执行顺序及trigger()与 triggerHandler()比较实例分析
2020/04/30 jQuery
javascript canvas时钟模拟器
2020/07/13 Javascript
dataframe 按条件替换某一列中的值方法
2019/01/29 Python
Python Pandas中根据列的值选取多行数据
2019/07/08 Python
python爬虫 模拟登录人人网过程解析
2019/07/31 Python
python3实现高效的端口扫描
2019/08/31 Python
浅谈Python中的字符串
2020/06/10 Python
css3.0 图形构成实例练习二
2013/03/19 HTML / CSS
HTML5 文件上传下载的实例代码
2017/07/03 HTML / CSS
Sunglasses Shop荷兰站:英国最大的太阳镜独立在线零售商和供应商
2017/01/08 全球购物
干部行政关系介绍信
2014/01/17 职场文书
师生聚会感言
2014/01/26 职场文书
八项规定整改措施
2014/02/12 职场文书
酒店总经理岗位职责范本
2014/08/08 职场文书
党的群众路线教育实践活动对照检查材料(教师)
2014/09/24 职场文书
房产销售独家委托书范本
2014/10/01 职场文书
大学生就业指导课心得体会
2016/01/15 职场文书
同学联谊会邀请函
2019/06/24 职场文书