Python上下文管理器
在Python中让自己创建的函数、类、对象支持with语句,就实现了上线文管理协议。我们经常使用with open(file, "a+") as f:这样的语句,无需手动调用f.close()关闭文件。这种用法不仅优雅,而且避免遗忘释放资源,十分方便。所以,当操作某些资源时,需要对资源的获取与释放进行自动操作,就可以用上线文管理器。比如:数据库的连接,查询,关闭处理;socket的连接和断开。本篇主要介绍,如何让自己创建的类、对象、函数等支持with语句,详细请看下文。
1 让对象支持上下文管理协议
在类中,实现 __enter__()和__exit__()方法,类创建的对象就支持with语句。如下:
class A:
def __enter__(self):
print("in __enter__")
return [1, 2, 3] def __exit__(self, exc_type, exc_val, exc_tb):
print("in __exit__") obj = A()
with obj as o:
print("看看o是什么:", o)
print("do something")
print("end")
注意本例的输出结果的顺序:
in __enter__
看看o是什么: [1, 2, 3]
do something
in __exit__
end
(1)当执行 with 语句的时候,对象的 __enter__() 方法被触发, 它返回的值(如果有的话)会被赋值给 as 声明的变量。对应输出应该是【in __enter__】和将[1,2,3]赋值给o【字母o】。
(2)然后,with 语句块里面的代码开始执行。对应的输出是【看看o是什么: [1, 2, 3]】和【do someting】。
(3)最后,__exit__() 方法被触发进行清理工作。对应的输出是【in __exit__】。
补充说明:
__exit__()方法的第三个参数包含了异常类型、异常值和追溯信息(如果有的话)。 __exit__()方法能自己决定怎样利用这个异常信息,或者忽略它并返回一个None值。
如果 __exit__() 返回 True ,那么异常会被清空,就好像什么都没发生一样, with 语句后面的程序继续在正常执行。
上面的例子还不支持多个with嵌套使用,下面是一个可以嵌套使用with语句的例子:
from socket import socket, AF_INET, SOCK_STREAM class Connection:
def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
self.address = address
self.family = family
self.type = type
self.connections = [] def __enter__(self):
sock = socket(self.family, self.type)
sock.connect(self.address)
self.connections.append(sock)
return sock def __exit__(self, exc_ty, exc_val, tb):
self.connections.pop().close() conn = Connection(('www.python.org', 80))
with conn as s1:
print(s1)
with conn as s2:
print(s2)
2 装饰器版上下文管理器
上面介绍了在类和对象中实现上下文管理协议,其实Python标准库中contextlib包的@contextmanager装饰器能够轻松实现一个上下文管理器,下例是用其实现统计代码块耗时的上下文管理器:
import time
from contextlib import contextmanager
# 来看一个装饰器版本的上下文管理器
# 检查代码消耗时间块
@contextmanager
def timecount(name):
start = time.time()
try:
yield
finally:
end = time.time()
print('{}: {}'.format(name, end - start)) with timecount('cost time:'):
time.sleep(2)
# cost time:: 2.000200033187866
timecount()中,yield之前的代码相当于__enter__()方法;yield 之后的代码相当于 __exit__()方法。如果有异常会自动在yield一行抛出。
上下文管理器可以应用在事务中:
# 更高级的事务管理
@contextmanager
def list_transaction(orig_list):
working = list(orig_list)
yield working
orig_list[:] = working lis = [1, 2, 3]
with list_transaction(lis) as work:
work.append(5)
work.append(6) print(lis)
# [1, 2, 3, 5, 6]
一旦with语句内有异常产生,之前的操作不会生效:
lis = [1, 2, 3]
with list_transaction(lis) as work:
work.append(5)
work.append(6)
print(lis)
raise RuntimeError("回滚")
如果在交互式命令行中打印lis,依然会发现lis的内容没有改变,也就是说,with语句中的代码出现异常,with语句中的操作都不会生效,只有with无异常退出,才会生效。对于事务管理来说是比较有用的。
3 小结
(1)当操作一些需要打开、连接、断开或释放的资源时,让对象或函数支持with语句十分方便、省事、优雅。如数据库的链接断开、套接字的连接断开、事务、锁资源等。
(2)类中实现__enter__()和__exit__()方法,即可实现上下文管理协议,对象可使用with语句。
(3)通过contextlib包中的@contextmanager装饰器装饰一个函数,该函数即可使用with语句。
Python上下文管理器的更多相关文章
- python 上下文管理器
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...
- Python 上下文管理器和else块
最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要.目前,我们只了解了上下文管理器的皮毛--Basic 语言有with 语句,而且很多语言都有.但是,在各种语言中 with 语句的 ...
- python上下文管理器ContextLib及with语句
http://blog.csdn.net/pipisorry/article/details/50444736 with语句 with语句是从 Python 2.5 开始引入的一种与异常处理相关的功能 ...
- Python上下文管理器 with
对于系统资源的操作,如:文件操作.数据库操作等,我们往往打开文件.连接数据库后忘了将其close掉,这时就可能会引发异常,因此我们常用的做法是: # coding:utf-8 f = open(&qu ...
- Python上下文管理器(Context managers)
上下文管理器(Context managers) 上下文管理器允许你在有需要的时候,精确地分配和释放资源. 使用上下文管理器最广泛的案例就是with语句了.想象下你有两个需要结对执行的相关操作,然后还 ...
- python上下文管理器细读
test 1 上下文管理器,将生成器转化为上下文管理器 import contextlib @contextlib.contextmanager def a(): print(1) yield pri ...
- 吃透Python上下文管理器
什么是上下文管理器? 我们常见的with open操作文件,就是一个上下文管理器.如: with open(file, 'rb') as f: text = f.read() 那上下文管理器具体的定义 ...
- python 上下文管理器contextlib.ContextManager
1 模块简介 在数年前,Python 2.5 加入了一个非常特殊的关键字,就是with.with语句允许开发者创建上下文管理器.什么是上下文管理器?上下文管理器就是允许你可以自动地开始和结束一些事情. ...
- Python 上下文管理器模块--contextlib
在 Python 处理文件的时候我们使用 with 关键词来进行文件的资源关闭,但是并不是只有文件操作才能使用 with 语句.今天就让我们一起学习 Python 中的上下文管理 contextlib ...
随机推荐
- 30分钟掌握ES6/ES2015核心内容(下)
在 30分钟掌握ES6/ES2015核心内容(上)我们讲解了es6最常用的一些语法:let, const, class, extends, super, arrow functions, templa ...
- java 集合框架(十四)Queue
一.概述 Queue一种队列结构集合,用来存储将要进行处理的元素.通常以FIFO的方式排序元素,但这并不是必须的.比如优先度队列就是一个例外,它是以元素的值来排序.但无论怎样,每个Queue的实现都必 ...
- 通用的Android控件抖动效果实现
这个小程序的功能在实际的开发中会用到,比如:设置Button左右晃动,或者上下的晃动效果,下面就给出示例代码. 首先:要定义一个xml文件,命名为Shake [html] view plain cop ...
- HDMI中的AVmute是什么功能
1. HDMI AVMute是HDMI TMDS数据岛周期General Control Packet中的一个标示. 2. AVMute字面意思是Audio Video Mute声音图像消隐,简单来说 ...
- R语言︱XGBoost极端梯度上升以及forecastxgb(预测)+xgboost(回归)双案例解读
XGBoost不仅仅可以用来做分类还可以做时间序列方面的预测,而且已经有人做的很好,可以见最后的案例. 应用一:XGBoost用来做预测 ------------------------------- ...
- 【linux】php安装 出现Sorry, I cannot run apxs. ***错误解决方法
首先, 通过错误提示, 我们得知"I cannot run apxs". 我一直以为是apxs安装有问题, 但找了很久仍未得到合理的解释和解决方法. 于是我直接运行"/u ...
- 个性化WinPE封装方法 ----最后实战“制作WinPE3.0图文教程”
经过前几讲,主要目的就是准备一些"原材料",熟悉一些"命令",实际上是"战前演练准备".下面要进入"实战状态",成败在此 ...
- java.text.ParseException: Unparseable date: "2015-06-09 hh:56:19"
1.错误描述 [DEBUG:]2015-06-09 16:56:19,520 [-------------------transcation start!--------------] java.te ...
- 零基础6个月学好java月薪1w+看看他是怎么学好java的
21世纪进入信息时代,信息科技给人类的生产和生活方式带来了深刻的变革,信息产业已成为推动国家经济发展的主导产业之一,Java作为含金量极高的一门IT技术,很多人希望从事这个行业,那么想学好Java,要 ...
- Java虚拟机的锁优化
1 锁偏向.当现成请求一个对象锁时,如果获得锁,则该对象锁进入偏向模式,当该线程再次请求该对象的锁时,无需再做任何同步操作. 可通过在Java虚拟机中开启参数-XX:+UseBasedLock开启偏向 ...