from __future__ import with_statement

简介

with是从2.5版本引入的一个语法. 这个语法本身是为了解决try..finally繁琐的释放各类资源(文件句柄, Lock等)的问题.

如果想在旧版本中使用这个功能, 直接引入future模块就可以.

1
from  __future__  import  with_statement

举例简单说明一下没有with和有with的代码区别

1
2
3
4
5
6
try:
    dict_file  =  open("dict_file_path")
    for  line  in  dict_file:
        print  line,   # do something
finally:
    dict_file.close()

用with-statement的方式如下

1
2
3
with  open("dict_file_path") as dict_file:
    for  line  in  dict_file:
        print  line,   # do something

明显使用了with之后语法更加简洁.

官方对于with-statement的定义如下

1
2
with_stmt ::=   "with"  with_item (","  with_item)*  ":"  suite
with_item ::=   expression ["as"  target]

从定义中, 我们可以看出, 如果想通过with使用多个资源的话, 可以使用下面的写法

1
with  open("d1_file") as d1,  open("d2_file") as d2:

as部分是可有可无的, 对于lock等这类资源来说一般都是这种用法

个人认为, with-statement是现在带有内存管理语言的折中处理方法, 对于c++来说, 可以使用RAII的方式, 一个类有明确的析构函数, 在超出作用域之后会被调用, 在析构函数内进行资源的释放是非常不错的选择. 也体现了c++的高效, 灵活和优雅.

Java, python这类语言都无法做到, 但是语言自身的异常机制都非常完善, 不像c++为了兼容c导致异常机制显得有点鸡肋. try..catch..finally就成为了这类语言用来进行资源释放的方式, GC(垃圾回收)回收内存的时间不确定, 无法利用RAII.

 

With-statement Magic Method

python语言层面上对于with的支持是通过magic method来实现的, 和一般的python特性一样.

使用PEP343中with-statement的定义来引入这两个magic method

1
2
with VAR  =  EXPR:
        BLOCK

直接翻译过来就是

1
2
3
4
5
6
VAR  =  EXPR
VAR.__enter__()
try:
        BLOCK
finally:
        VAR.__exit__()

我们可以清楚的看到这两个magic method分别是__enter__和__exit__, 一个在进入with-statement block的时候初始化, 一个在离开的时候进行cleanup工作.

下面来举一个简单的timer例子.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import  time
 
class  Timer(object):
    def  __init__(self):
        pass
 
    def  __enter__(self):
        self.start  =  time.time()
 
    def  __exit__(self, exception_type, exception_val, trace):
        print  "elapsed:", time.time()  -  self.start
 
if  __name__  ==  "__main__":
    with Timer():
        [i  for  i  in  xrange(10000000)]

运行结果如下:

1
elapsed:  1.32907581329

timer是一个简单实用的类, 在编写性能测试代码的时候, 经常会用到.

水平有限, 欢迎拍砖!

 

2014.4.19 添加一个with带有异常处理的demo

 以一个操作数据库的session为例, 下面的方式可以替代繁琐的try...except...finally语句, 可以包装sqlalchemy的session.

笔者用这个简单的封装作为sqlalchemy来方便处理session相关的操作. commit操作需要自己去调用, 也可以加入到exit方法中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class  Wrapper(object):
    '''A context manager to automatically close an object with a close method
    in a with statement.'''
 
    def  __init__(self, obj):
        self.obj  =  obj
 
    def  __enter__(self):
        return  self.obj   # bound to target
 
    def  __exit__(self, exception_type, exception_val, trace):
        if  exception_type:
            try:
                self.obj.rollback()
            except  AttributeError:   # obj cannot rollback
                return  True   # exception handled successfully
        try:
            self.obj.close()
        except  AttributeError:   # obj isn't closable
            return  True   # exception handled successfully   

  

 

参考文献:

  1. PEP343: http://www.python.org/dev/peps/pep-0343/
  2. Python Docs <Compound statements>: http://docs.python.org/2/reference/compound_stmts.html#the-with-statement

你可能感兴趣的:(from __future__ import with_statement)