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编写web API的教程
Apr 30 Python
python实现的用于搜索文件并进行内容替换的类实例
Jun 28 Python
Python爬虫DOTA排行榜爬取实例(分享)
Jun 13 Python
python爬取拉勾网职位数据的方法
Jan 24 Python
Python2.7 实现引入自己写的类方法
Apr 29 Python
Python类的继承用法示例
Jan 31 Python
python设计微型小说网站(基于Django+Bootstrap框架)
Jul 08 Python
Django 对象关系映射(ORM)源码详解
Aug 06 Python
Python 多线程,threading模块,创建子线程的两种方式示例
Sep 29 Python
使用Python求解带约束的最优化问题详解
Feb 11 Python
Python发送邮件实现基础解析
Aug 14 Python
python 中关于pycharm选择运行环境的问题
Oct 31 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下关于Cannot use a scalar value as an array的解决办法
2010/08/08 PHP
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
无JS,完全php面向过程数据分页实现代码
2012/08/27 PHP
PHP互换两个变量值的方法(不用第三变量)
2016/11/14 PHP
Yii输入正确验证码却验证失败的解决方法
2017/06/06 PHP
游戏人文件夹程序 ver 3.0
2006/07/14 Javascript
JS创建优美的页面滑动块效果 - Glider.js
2007/09/27 Javascript
JavaScript中去掉数组中的重复值的实现方法
2011/08/03 Javascript
js改变img标签的src属性在IE下没反应的解决方法
2013/07/23 Javascript
超简单JS二级、多级联动的简单实例
2014/02/18 Javascript
angularjs学习笔记之双向数据绑定
2015/09/26 Javascript
vue2.0实战之基础入门(1)
2017/03/27 Javascript
Ajax高级笔记 JavaScript高级程序设计笔记
2017/06/22 Javascript
JS模拟超市简易收银台小程序代码解析
2017/08/18 Javascript
浅谈node的事件机制
2017/10/09 Javascript
jquery ztree实现右键收藏功能
2017/11/20 jQuery
JavaScript学习笔记之DOM操作实例分析
2019/01/08 Javascript
Vue加载json文件的方法简单示例
2019/01/28 Javascript
JavaScript闭包相关知识解析
2019/10/19 Javascript
[00:57]深扒TI7聊天轮盘语音出处5
2017/05/11 DOTA
python正则表达式面试题解答
2020/04/28 Python
pandas 层次化索引的实现方法
2019/07/06 Python
python实现静态web服务器
2019/09/03 Python
基于django2.2连oracle11g解决版本冲突的问题
2020/07/02 Python
numpy实现RNN原理实现
2021/03/02 Python
5 个强大的HTML5 API 函数推荐
2014/11/19 HTML / CSS
英国家庭和商业健身器材购物网站:Fitness Options
2018/07/05 全球购物
美国在线奢侈品寄售商店:Luxury Garage Sale
2018/08/19 全球购物
阿联酋优惠券服务:Living Kool
2019/12/12 全球购物
几道PHP的面试题
2012/05/19 面试题
新媒传信软件测试面试题
2013/02/24 面试题
介绍一下EJB的分类及其各自的功能及应用
2016/08/23 面试题
酒店秘书求职信范文
2014/02/17 职场文书
装修公司工程部经理岗位职责
2015/04/09 职场文书
MySQL高速缓存启动方法及参数详解(query_cache_size)
2021/07/01 MySQL
解决Python保存文件名太长OSError: [Errno 36] File name too long
2022/05/11 Python