Python 的 with 语句(2)
我们经常既想利用with语句的便利,又不想很麻烦的写一个类来实现__enter__() 和 __exit__()方法,有什么比较现成的办法呢? Python的标准库里引入了contextlib 模块可以解决这个问题。contextlib 模块提供了装饰器contextmanager,使用这个,可以对已有的生成器函数或者对象进行包装,加入对上下文管理协议的支持,避免了专门编写上下文管理器来支持 with 语句。 contextmanager 用于对生成器函数进行装饰,生成器函数被装饰以后,返回的是一个上下文管理器,其 enter() 和 exit() 方法由 contextmanager 负责提供。被装饰的生成器函数只能产生一个值,否则会导致异常 RuntimeError,产生的值会赋值给 as 子句中的 target,如果使用了 as 子句的话。from contextlib import contextmanager
@contextmanager
def demo():
print '[Allocate resources]'
print 'Code before yield-statement executes in __enter__'
yield '*** contextmanager demo ***'
print 'Code after yield-statement executes in __exit__'
print '[Free resources]'
with demo() as value:
print 'Assigned Value: %s' % value
[Allocate resources]
Code before yield-statement executes in __enter__
Assigned Value: *** contextmanager demo ***
Code after yield-statement executes in __exit__
[Free resources]
def contextmanager(func):
"""@contextmanager decorator.
Typical usage:
@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>
This makes this:
with some_generator(<arguments>) as <variable>:
<body>
equivalent to this:
<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
"""
@wraps(func)
def helper(*args, **kwds):
return GeneratorContextManager(func(*args, **kwds))
return helper
class Box(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print("Box " + self.name + " Opened")
return self
def __exit__(self, exception_type, exception, traceback):
all_none = all(
arg is None for arg in [exception_type, exception, traceback]
)
if (not all_none):
print("Exception: \"%s\" raised." %(str(exception)))
print("Box Closed")
print("")
return all_none
#===============================================================
if (__name__ == "__main__"):
with Box("tupperware") as simple_box:
print("Nothing in " + simple_box.name)
with Box("Pandora's") as pandoras_box:
raise Exception("All the evils in the world")
print("end")
2017-02-25 20:16:49