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的*args和**kwargs用法
Nov 01 Python
Python用sndhdr模块识别音频格式详解
Jan 11 Python
python写入并获取剪切板内容的实例
May 31 Python
python实现文件助手中查看微信撤回消息
Apr 29 Python
python实现截取屏幕保存文件,删除N天前截图的例子
Aug 27 Python
Numpy的简单用法小结
Aug 28 Python
使用python和pygame制作挡板弹球游戏
Dec 03 Python
关于python中的xpath解析定位
Mar 06 Python
如何理解python面向对象编程
Jun 01 Python
django 实现后台从富文本提取纯文本
Jul 02 Python
mac安装python3后使用pip和pip3的区别说明
Sep 01 Python
Python连续赋值需要注意的一些问题
Jun 03 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
跟我学Laravel之快速入门
2014/10/15 PHP
laravel学习教程之关联模型
2016/07/30 PHP
php组合排序简单实现方法
2016/10/15 PHP
Yii 2.0在Grid中格式化时间方法示例
2017/06/06 PHP
php 算法之实现相对路径的实例
2017/10/17 PHP
PHP模版引擎原理、定义与用法实例
2019/03/29 PHP
PHP执行系统命令函数实例讲解
2021/03/03 PHP
Js 获取HTML DOM节点元素的方法小结
2009/04/24 Javascript
javascript 隔行换色函数代码
2010/10/24 Javascript
理解JavaScript中的对象 推荐
2011/01/09 Javascript
基于Jquery实现的一个图片滚动切换
2012/06/21 Javascript
纯JavaScript实现HTML5 Canvas六种特效滤镜示例
2013/06/28 Javascript
js弹出确认是否删除对话框
2014/03/27 Javascript
jQuery CSS()方法改变现有的CSS样式
2014/08/20 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
JavaScript中的DSL元编程介绍
2015/03/15 Javascript
JavaScript常用基础知识强化学习
2015/12/09 Javascript
Bootstrap 模态框(Modal)带参数传值实例
2017/08/20 Javascript
微信小程序实现跳转的几种方式总结(推荐)
2019/04/24 Javascript
JavaScript实现更换背景图片
2019/10/18 Javascript
浅析vue-router中params和query的区别
2019/12/24 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
[02:12]探秘2016国际邀请赛中国区预选赛选手房间
2016/06/25 DOTA
用Python编写一个简单的CS架构后门的方法
2018/11/20 Python
python各类经纬度转换的实例代码
2019/08/08 Python
Python脚本破解压缩文件口令实例教程(zipfile)
2020/06/14 Python
Python日志打印里logging.getLogger源码分析详解
2021/01/17 Python
存储过程和函数的区别
2013/05/28 面试题
公司节能减排倡议书
2014/05/14 职场文书
2014年教务工作总结
2014/12/03 职场文书
售后服务承诺函格式
2015/01/21 职场文书
先进基层党组织主要事迹材料
2015/11/03 职场文书
小学家庭教育心得体会
2016/01/14 职场文书
Mysql实现主从配置和多主多从配置
2021/06/02 MySQL
SpringBoot整合Mybatis Generator自动生成代码
2021/08/23 Java/Android
SQL Server中的游标介绍
2022/05/20 SQL Server