with 语句的作用

with 语句的基本作用:构建对资源创建与释放的

with open('a','r) as f:
    for line in f:
        print line.strip()

以上代码使用with as 语句来操作一个文件,其作用为 打开一个文件,如果一切正常则,将文件对下赋值给f,然后使用迭代器遍历文件中的每一行,当最终遍历完成后,再关闭文件。且即使发生了异常,该文件仍然会被关闭。

with执行原理

当with 执行时,执行 上下文表达式(context_expr) 来获得一个上下文管理器,上下文管理器的职责是提供一个上下文对象,用于在with语句块中处理细节:
1、 一旦获取的上下文对象,就会调用它的 enter() 方法,将完成 with语句 块执行前的所有准备功能工作。
2、如果with 语句后面跟了 as 语句,则用 enter() 方法的返回值来赋值;
3、当with语句块结束时,无论是正常结束,还是由于异常,都会调用上下文对象的__exit__()方法,exit()方法有3个参数,如果with语句正常结束,三个参数全部都是 None;如果发生异常,三个参数的值分别等于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象。

with支持对象

通过以上的原理可以知道,我们不能对任意的python 对象都使用 with 语句, 对象需要支持 上下文管理协议。
也就是说,只有内建了“上下文管理”的对象可以和with一起工作,目前支持该协议的对象有:

file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore    

with语句的自我实现

通过以上的运行原理可知,我们可以在类中自行创建 enter() 和 exit() 方法,来配合 with 语句创建类实例:

class Test:
    def __enter__(self):
        print 'begin connect ...'
    
    def __exit__(self,exc_type, exc_val, exc_tb):
        print 'close connect...'

if __name__ == '__main__':
    with Test() as f:
        print 'run...'

with语句的自我实现

通过调用 python 的 contextlib 模块,可以不需要构造含有 enter,exit 的类就可以使用with, 注意需结合yield 使用 (目前仅知道该用法)

from contextlib import contextmanager

@contextmanager
def test():
    print 'begin connect ...'
    yield 'ddd'
    print 'close connect...'

if __name__ == '__main__':
    #未赋值,则不输出函数中的返回值
    with test():
        print 'a'
        #赋值,输出函数中的返回值
    with test() as f:
        print f
        print 'a'

python 上下文管理协议

上下文管理协议 即 enter 和 exit

python 上下文管理器(Contextor)

上下文管理器即 实现了 上下文管理协议,当Contextor 调用/实例化时,则创建了 上下文管理器,类似实现迭代器协议类调用生成迭代器一样。运行的执行原理:

1、执行contextor 以获取上下文管理器
2、加载上下文管理器的exit()方法,备用
3、调用上下文管理器的enter()方法
4、如果有 as 语句,则将enter() 方法的返回值赋值给 变量名
5、执行语句with 中的代码
6、调用上下文管理器的 exit() 方法,如果退出使用由于异常导致的,那么该异常的 type、value 和 traceback 会作为参数传给 exit(),否则传三个 None