with语句支持在一个叫上下文管理器的对象的控制下执行一系列语句,语法大概如下:

with context as var:
statements

其中的context必须是个上下文管理器,它实现了两个方法__enter__,__exit__。

1.需求是怎么产生的

在正常的管理各种系统资源(文件、锁定和连接),在涉及到异常时通常是个棘手的问题。异常很可能导致控制流跳过负责释放关键资源的语句。

看一段简单的文件写入代码:

filename = 'my_file.txt'
f = open(filename,'w')
f.write('Hello ')
f.write('World')
f.close()

如果发生了意外的情况,例如写入'World'时磁盘空间不足,就会抛出异常,那么close()语句将不会被执行。

一般的解决方案是使用try-finally语句:

try:
filename = 'my_file.txt'
f = open(filename,'w')
f.write('Hello ')
f.write('World')
finally:
f.close()

但随着语句的增多,try-finally显然不够简洁,用with-as语句可以很简洁的实现以上功能:

with open('my_file','w') as f:
f.write('Hello ')
f.write('World')

这样不仅能处理出现异常的情况,而且还避免了在open一个文件后忘记了写close()方法的情况。

线程中的锁其实也实现了上下文管理协议:

import threading
with threading.Lock():
# 关键部分
statements
# 关键部分结束

再也不怕忘记将锁释放了。

2.上下文管理器的实现

上下文管理器要实现__enter__和__exit__的特殊方法。

__enter__(self): 进入上下文管理器时调用此方法,其返回值将被放入with-as语句中as说明符指定的变量中。

__exit__(self,type,value,tb):离开上下文管理器调用此方法。如果有异常出现,type、value、tb分别为异常的类型、值和追踪信息。如果没有异常,

3个参数均设为None。此方法返回值为True或者False,分别指示被引发的异常得到了还是没有得到处理。如果返回False,引发的异常会被传递出上下文。

文件上下文管理协议大概是如下实现的:

class OpenFile(object):
def __init__(self,filename,mode):
self.filename=filename
self.mode=mode
def __enter__(self):
self.f=open(self.filename,self.mode)
return self.f #作为as说明符指定的变量的值
def __exit__(self,type,value,tb):
self.f.close()
return False #异常会被传递出上下文
with OpenFile('my_file.txt','w') as f:
f.write('Hello ')
f.write('World')

  相当于

try :
执行__enter__的内容
finally:
执行__exit__的内容

3.异常的处理 

__exit__函数就能够拿到关于异常的所有信息(异常类型,异常值以及异常追踪信息),这些信息将帮助异常处理操作。

class ListTrans(object):
def __init__(self,alist):
self.alist=alist
def __enter__(self):
self.thecopy=list(self.alist)
return self.thecopy
def __exit__(self,exc_type,value,tb):
if exc_type is None:
self.alist[:]=self.thecopy
return False

没有异常发生时:

alist=[]
with ListTrans(alist) as working:
working.append(1)
working.append(2)
print alist

生成:

[1, 2]

有异常发生时:

alist=[]
with ListTrans(alist) as working:
working.append(1)
working.append(2)
raise RuntimeError('we are hosed')
print alist

生成:

RuntimeError: we are hosed

alist无变化。

可以捕捉异常:

alist=[]
try:
with ListTrans(alist) as working:
working.append(1)
working.append(2)
raise RuntimeError('we are hosed')
except RuntimeError as e:
print e
print alist

生成:

we are hosed
[]

当然,也可以简单的将__exit__的返回值设为True来忽略异常。

4.contextmanager装饰器

@contextmanager

contextlib模块的contextmanager装饰器可以更方便的实现上下文管理器。

任何能够被yield关键词分割成两部分的函数,都能够通过装饰器装饰的上下文管理器来实现。任何在yield之前的内容都可以看做在代码块执行前的操作,

而任何yield之后的操作都可以放在exit函数中。

from contextlib import contextmanager
@contextmanager
def listTrans(alist):
thecopy=list(alist)
yield thecopy
alist[:]=thecopy
alist=[]
with listTrans(alist) as working:
working.append(1)
working.append(2)
print alist

yield返回的值相当于__enter__的返回值。

要注意的是,这不是异常安全的写法,也就是说,当出现异常时,yield后的语句是不会执行的,想要异常安全,可用try捕捉异常:

from contextlib import contextmanager
@contextmanager
def listTrans(alist):
thecopy=list(alist)
try:
yield thecopy
except RuntimeError:
pass
alist[:]=thecopy
alist=[]
with listTrans(alist) as working:
working.append(1)
working.append(2)
raise RuntimeError

nested与closing

contextlib模块还有两个好玩的方法:nested,closing。

nested:用来更方便的减少嵌套写法:

当要嵌套的写上下文管理器时:

with open('toReadFile', 'r') as reader:
with open('toWriteFile', 'w') as writer:
writer.writer(reader.read())

可以用nested简化写法:

with contextlib.nested(open('fileToRead.txt', 'r'),
open('fileToWrite.txt', 'w')) as (reader, writer):
writer.write(reader.read())

python2.7后nested就过时了:

with open('fileToRead.txt', 'r') as reader,open('fileToWrite.txt', 'w') as writer:
writer.write(reader.read())

closing(object):创建上下文管理器,在执行过程离开with语句时自动执行object.close():

class Door(object) :
def open(self) :
print 'Door is opened'
def close(self) :
print 'Door is closed'
with contextlib.closing(Door()) as door :
door.open()

python上下文管理器及with语句的更多相关文章

  1. python上下文管理器ContextLib及with语句

    http://blog.csdn.net/pipisorry/article/details/50444736 with语句 with语句是从 Python 2.5 开始引入的一种与异常处理相关的功能 ...

  2. Python核心技术与实战——二一|巧用上下文管理器和with语句精简代码

    我们在Python中对于with的语句应该是不陌生的,特别是在文件的输入输出操作中,那在具体的使用过程中,是有什么引伸的含义呢?与之密切相关的上下文管理器(context manager)又是什么呢? ...

  3. Python上下文管理器你学会了吗?

    ​什么是上下文管理器 对于像文件操作.连接数据库等资源管理的操作,我们必须在使用完之后进行释放,不然就容易造成资源泄露.为了解决这个问题,Python的解决方式便是上下文管理器.上下文管理器能够帮助你 ...

  4. Python中的上下文管理器和with语句

    Python2.5之后引入了上下文管理器(context manager),算是Python的黑魔法之一,它用于规定某个对象的使用范围.本文是针对于该功能的思考总结. 为什么需要上下文管理器? 首先, ...

  5. Python进阶(上下文管理器与with语句)

    /*上下文管理器必须有__enter__和__exit__方法*/ class MyResource: def __enter__(self): print('链接资源') return self / ...

  6. python 上下文管理器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 上下文管理器(context manager)是Python2.5开始支持的一种语 ...

  7. Python 上下文管理器和else块

    最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要.目前,我们只了解了上下文管理器的皮毛--Basic 语言有with 语句,而且很多语言都有.但是,在各种语言中 with 语句的 ...

  8. Python上下文管理器

    在Python中让自己创建的函数.类.对象支持with语句,就实现了上线文管理协议.我们经常使用with open(file, "a+") as f:这样的语句,无需手动调用f.c ...

  9. Python上下文管理器 with

    对于系统资源的操作,如:文件操作.数据库操作等,我们往往打开文件.连接数据库后忘了将其close掉,这时就可能会引发异常,因此我们常用的做法是: # coding:utf-8 f = open(&qu ...

随机推荐

  1. Android,使用Intent或Bundle传递参数,跳转页面。

    (1)使用Intent跳转页面: 第一个activity:MainActivity.java中: Intent myIntent = new Intent(); myIntent.putExtra(& ...

  2. 【转】java静态代码块和构造方法执行顺序

    先看看下面几个类,然后判断它们的输出public class A { static{System.out.print(1);}public A(){System.out.print(2);}} pub ...

  3. 给iOS 模拟器“安装”app文件

    前言 刚刚接触iOS的时候,我就一直很好奇,模拟器上面能不能直接安装app呢?如果可以,我们就直接在模拟器上面聊QQ和微信了.直到昨天和朋友们聊到了这个话题,没有想到还真的可以给模拟器“安装”app! ...

  4. quartz定时任务中常用的cron表达式

    一:定时cron的格式,一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素. 按顺序依次为: 1.秒(0~59) 2.分钟(0~59) 3.小时(0~23) 4.天(月(0~31,但是你需 ...

  5. tomcat服务器使用简介

    tomcat服务器的应用与部署:1:下载tomcat服务器可以到http://tomcat.apache.org/下载apache服务器,左侧有各种版本的服务器,可以根据自己的需要下载,如果是是Lin ...

  6. /lib /usr/lib /usr/local/lib 区别

    简单说,/lib是内核级的,/usr/lib是系统级的,/usr/local/lib是用户级的. /lib/ — 包含许多被 /bin/ 和 /sbin/ 中的程序使用的库文件.目录 /usr/lib ...

  7. linux 中的vim的配置文件的位置

    /etc下面也有一个vimrc:这个文件对所有用户都有效 在用户家目录(/home/用户名:或/root/)下面有一个.viminfo,只针对特定的用户有效

  8. hackerrank Day15: Linked List

    #include <iostream> #include <cstddef> using namespace std; class Node { public: int dat ...

  9. 前端基础系列——CSS规范(文章内容为转载)

    原作者信息 作者:词晖 链接:http://www.zhihu.com/question/19586885/answer/48933504 来源:知乎 著作权归原作者所有,转载请联系原作者获得授权. ...

  10. 【JavaScript权威指南(第五版)】笔记之第一部分 核心javascript (第1章~第12章)

    第一章 javascript概述 ①.javascript是一种松散类型语言;也是一种解释型语言;         第二章 词法结构 ①.大小写敏感         第三章 数据类型和值 ①.isFi ...