标签:
with语句可以通过很简单的方式来替try/finally
语句。 with语句中EXPR部分必须是一个包含__enter__()
和__exit__()
方法的对象,也就是Context Manager。使用with语句的目的:
下述例子描述with...as语句的实现原理:
实现原理:
__enter__()
和__exit__()
方法的对象(Context Manager)。__enter__()
方法申请资源并将结果赋值给VAR变量。try/except
确保代码块BLOCK正确调用,否则调用EXPR的__exit__()
方法退出并释放资源。__exit__()
方法释放资源。EXPR可以使用with语句的前提,必须是一个包含__enter__()
和__exit()__
方法的对象(Context Manager),最直接的方式是声明一个对象,在__enter__()
方法里面申请资源,在__exit__()
方法里面释放资源;EXPR返回此对象。
更通用和更高效的将普通的函数转变为包含__enter__()
和__exit__()
方法的对象的方法是:通过一个特定的decorator(@contextmanager)扩展该函数并将函数声明为非循环的单一返回值的generator。
generator可以将函数变成类似于iterator,每次调用好像通过iterator的next逐步读取,而不是一次返回。
- 比实现一个iterator简单,iterator需要实现
__init__
,__iter__
,__next__
函数。- 比将结果一次返回(全部读取到内存中)要节省内存,通过next可以逐步获取需要的值。
@contextmanagerdecorator的实现原理:
声明contextmanager的decorator函数。参数是generator,返回值是一个接受和generator函数同样参数并且将generaor函数和参数传递到Context Manager构造函数并返回Context Manager对象的函数。绕死了!!!
decorator函数,是接受函数作为参数,并且返回一个函数的的函数。当对函数func进行此修饰时相当于对func进行一次转变: func = decorator(func),在这里generator被修饰后变成了
help(*args, **kwargs)
函数
在__enter__()
方法中使用generator的next()方法获取第一个返回值。如果gen并不是generator函数,抛出一个runtime异常。
__exit__()
方法中,如果存在异常将异常跑出,否则继续调用generator的next()方法。因此generator是一个具有唯一值非loop的generator因此会抛出stopiteration异常(正常预期值),否则抛出一个runtime异常。上述并没有涉及到资源的申请和释放,因此在generator函数里面,第一个loop即__enter__()
函数调用时,进行资源的申请,第二个loop也就是__exit__()
函数调用时抛出异常进入finally模块释放资源。下面是应用示例:
如上所述,就是with语句以及contextmanager decorator修饰器的语法解析。标准库里有些对象已经是context manager了,例如:
- file
- thread.LockType
- threading.Lock
- threading.RLock
- threading.Condition
- threading.Semaphore
- threading.BoundedSemaphore
另外我们也可以通过contextlib.contextmanager来修饰我们的generator函数,作为context manager使用在with语句中。
标签:
原文地址:http://www.cnblogs.com/3days/p/5236087.html