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 ...
随机推荐
- JQuery基础知识学习1
1.JQuery是javascript的类库 2.下载JQuery 3.导入JQuery <script src="jquery-3.0.0.js"></scri ...
- python 爬取糗事百科 gui小程序
前言:有时候无聊看一些搞笑的段子,糗事百科还是个不错的网站,所以就想用Python来玩一下.也比较简单,就写出来分享一下.嘿嘿 环境:Python 2.7 + win7 现在开始,打开糗事百科网站,先 ...
- vim编辑器——常用操作整理
注意:以下的操作都是在命令状态下进行的,不要进入插入状态了.参考这里 1.删除 dd 删除一行 ndd 删除以当前行开始的n行dw 删除以当前字符开始的一个字符ndw 删除 ...
- 支付宝wap支付调起客户端
https://mclient.alipay.com/home/exterfaceAssign.htm?alipay_exterface_invoke_assign_client_ip=183.15. ...
- Ubuntu 卸载cario-dock
偶然间听说别人用dock 可以把ubuntu美化,结果就装了个cairo-dock .结果是苹果mac的风格.不是很喜欢.于是就卸载,卸载过程中.发行卸载不掉. 尝试了很多方法. sudo apt-g ...
- Error Code: 1318. Incorrect number of arguments for PROCEDURE student.new_procedure; expected 0, got
1.错误描述 13:58:20 call new_procedure('2000','zhangsan') Error Code: 1318. Incorrect number of argument ...
- 使用NPOI导入导出标准Excel
尝试过很多Excel导入导出方法,都不太理想,无意中逛到oschina时,发现了NPOI,无需Office COM组件且不依赖Office,顿时惊为天人,怀着无比激动的心情写下此文. 曾使用过的方法 ...
- C#中string类型是值类型还是引用类型?
.Net框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一个引用类型,也就是说线程上的堆栈上不会驻留有任何字符串. string类型(引用类型) 名称 CT ...
- VS Visual Studio 入门技巧
0.在VS常用快捷键 F1: 调出当前光标所在处关键字的帮助文档 F5: 编译及运行 Ctrl+F5: 编译及运行(不调试) F6: 生成解决方案,用来检查语法错误 F7: ...
- 使用Restify+superagent做数据转发
最近为了解决跨域问题,做了一个Node数据转发服务器,使用到了Restify和superagent. Restify 是nodejs的模块.虽然restify的API或多或少的参考了express,但 ...