如何在新函数中组合Python上下文管理器?
假设我有两个: 在Python 2.7中,我可以在如下代码块中使用这两种代码:如何在新函数中组合Python上下文管理器?,python,python-2.7,Python,Python 2.7,假设我有两个: 在Python 2.7中,我可以在如下代码块中使用这两种代码: def do_something(): with foo(), bar(): [...] 但是,如何将这两种方法组合成一个单一上下文管理器(为了简洁明了): 我不认为我可以简单地打电话给另外两个上下文管理器,期望它能起作用: @contextmanager def foobar(): # Wrong(?) foo() bar() 由于要成为上下文管理器,基本上需要在
def do_something():
with foo(), bar():
[...]
但是,如何将这两种方法组合成一个单一上下文管理器(为了简洁明了):
我不认为我可以简单地打电话给另外两个上下文管理器,期望它能起作用:
@contextmanager
def foobar():
# Wrong(?)
foo()
bar()
由于要成为上下文管理器,基本上需要在某些点上调用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuuuu
如果坚持使用contextlib.contextmanager
,请再次复制:
被修饰的函数在调用时必须返回生成器迭代器。此迭代器必须只生成一个值,该值将绑定到with语句的as子句中的目标(如果有)
在生成器生成时,将执行with语句中嵌套的块。然后,在模块退出后,发电机恢复运行。如果块中发生未处理的异常,则会在发生屈服点的生成器内部重新调用该异常。因此,您可以使用try…except…finally语句来捕获错误(如果有),或者确保进行一些清理。如果捕获异常只是为了记录它或执行某些操作(而不是完全抑制它),则生成器必须重新释放该异常。否则,生成器上下文管理器将向with语句指示异常已被处理,并将在with语句之后立即使用该语句继续执行
看起来这是可行的,尽管我不确定是否所有角落的案件都得到了处理:
from contextlib import contextmanager
@contextmanager
def bar():
try:
print 'enter bar'
yield
finally:
print 'exit bar'
@contextmanager
def foo():
try:
print 'enter foo'
yield
finally:
print 'exit foo'
@contextmanager
def foobar():
try:
with foo(), bar():
print 'enter foobar'
yield
finally:
print 'exit foobar'
with foobar():
print 'hey'
enter foo
enter bar
enter foobar
hey
exit bar
exit foo
exit foobar
您可以将多个上下文管理器组合到一个嵌套的上下文管理器中,但它是从2.7版开始的。
with
语句正在执行嵌套的工作。更多信息。您可以使用contextlib.nested
(包装在lambda中,以延迟创建单独的上下文管理器)。但是,Python2.7中不推荐使用此函数,因为在一个with
语句中可以有多个上下文管理器。使用两个不同的上下文管理器不会重复您自己的操作,除非您经常和/或专门使用这两个上下文管理器
something = lambda : contextlib.nested(foo(), bar())
with something():
# ...
(有些人可能不喜欢在此处使用lambda
代替def
语句:
def something():
return contextlib.nested(foo(), bar())
)调用两个不同的上下文管理器不会重复您自己的操作。将它们结合起来似乎是不必要的,除非你经常同时使用它们。
from contextlib import contextmanager
@contextmanager
def bar():
try:
print 'enter bar'
yield
finally:
print 'exit bar'
@contextmanager
def foo():
try:
print 'enter foo'
yield
finally:
print 'exit foo'
@contextmanager
def foobar():
try:
with foo(), bar():
print 'enter foobar'
yield
finally:
print 'exit foobar'
with foobar():
print 'hey'
enter foo
enter bar
enter foobar
hey
exit bar
exit foo
exit foobar
something = lambda : contextlib.nested(foo(), bar())
with something():
# ...
def something():
return contextlib.nested(foo(), bar())