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之有点简约的元组
Sep 24 Python
Python 自动补全(vim)
Nov 30 Python
Python处理JSON数据并生成条形图
Aug 05 Python
Python中遇到的小问题及解决方法汇总
Jan 11 Python
python 接口测试response返回数据对比的方法
Feb 11 Python
如何用Python实现简单的Markdown转换器
Jul 16 Python
不管你的Python报什么错,用这个模块就能正常运行
Sep 14 Python
Django 后台获取文件列表 InMemoryUploadedFile的例子
Aug 07 Python
python3 使用Opencv打开USB摄像头,配置1080P分辨率的操作
Dec 11 Python
浅谈TensorFlow之稀疏张量表示
Jun 30 Python
python批量修改文件名的示例
Sep 27 Python
Python 里最强的地图绘制神器
Mar 01 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
动漫女神老婆无限好,但日本女生可能就不是这么一回事了!
2020/03/04 日漫
php笔记之:初探PHPcms模块开发介绍
2013/04/26 PHP
php+ajax实现无刷新的新闻留言系统
2020/12/21 PHP
php用户注册信息验证正则表达式
2015/11/12 PHP
laravel-admin 管理平台获取当前登陆用户信息的例子
2019/10/08 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
php在linux环境中如何使用redis详解
2020/12/15 PHP
jQuery Ajax使用 全解析
2010/12/15 Javascript
jquery焦点图片切换(数字标注/手动/自动播放/横向滚动)
2013/01/24 Javascript
让页面上两个div中的滚动条(滑块)同步运动示例
2013/08/07 Javascript
JavaScript常用的返回,自动跳转,刷新,关闭语句汇总
2015/01/13 Javascript
jQuery焦点图切换特效代码分享
2015/09/15 Javascript
js如何判断输入字符串长度
2015/12/16 Javascript
基于Jquery插件实现跨域异步上传文件功能
2016/04/26 Javascript
微信小程序 欢迎页面的制作(源码下载)
2017/01/09 Javascript
NodeJs下的测试框架Mocha的简单介绍
2017/02/22 NodeJs
将angular-ui的分页组件封装成指令的方法详解
2017/05/10 Javascript
vue将毫秒数转化为正常日期格式的实例
2018/09/16 Javascript
vue-cli项目中使用echarts图表实例
2018/10/22 Javascript
Layui动态生成select下拉选择框不显示的解决方法
2019/09/24 Javascript
javascript递归函数定义和用法示例分析
2020/07/22 Javascript
详解Python的Django框架中inclusion_tag的使用
2015/07/21 Python
python实现kMeans算法
2017/12/21 Python
django2.2安装错误最全的解决方案(小结)
2019/09/24 Python
python编写扎金花小程序的实例代码
2021/02/23 Python
HTML+CSS3+JS 实现的下拉菜单
2020/11/25 HTML / CSS
警察思想汇报
2014/01/04 职场文书
购房意向书
2014/04/01 职场文书
《他得的红圈圈最多》教学反思
2014/04/24 职场文书
支部组织生活会方案
2014/06/10 职场文书
幼儿园园长个人总结
2015/03/02 职场文书
山楂树之恋观后感
2015/06/11 职场文书
英文诗歌翻译方法(赏析)
2019/08/16 职场文书
B站评分公认最好看的动漫,你的名字评分9.9,第六备受喜欢
2022/03/18 日漫
Python获取字典中某个key的value
2022/04/13 Python
SQL Server中搜索特定的对象
2022/05/25 SQL Server