【发布时间】:2018-05-22 04:20:30
【问题描述】:
将上下文管理器定义为函数,很容易以编程方式从一个内部输入一个单独的(或递归的)上下文管理器,如下所示:
@contextmanager
def enter(times):
if times:
with enter(times - 1) as tup:
print 'entering {}'.format(times)
yield tup + (times,)
print 'exiting {}'.format(times)
else:
yield ()
运行这个:
In [11]: with enter(4) as x:
....: print x
....:
entering 1
entering 2
entering 3
(1, 2, 3)
exiting 3
exiting 2
exiting 1
所有的出入境簿记都为您完成,真好!但是如果你有一个类而不是一个函数呢?
class Enter(object):
def __init__(self, times):
self.times = times
def __enter__(self):
print 'entering {}'.format(self.times)
if self.times:
with Enter(self.times - 1) as tup: # WRONG
return tup + (self.times,)
return ()
def __exit__(self, *_):
print 'exiting {}'.format(self.times)
运行这个是错误的,因为你在运行 with-block 中的任何代码之前输入并退出嵌套调用:
In [12]: with Enter(3) as tup:
print tup
....:
entering 3
entering 2
entering 1
entering 0
exiting 0
exiting 1
exiting 2
(1, 2, 3)
exiting 3
规定:不能强迫客户自己使用ExitStack;内部调用必须像在生成器中一样被封装。涉及Enter 维护自己的私有堆栈的解决方案也是次优的(在现实生活中,内部__exit__ 调用必须以线程安全的方式匹配到内部__enter__ 调用,但我会即使在这个简单的示例中,也希望尽可能避免这种手动记账。)
【问题讨论】:
-
你不能在你的
__enter__()方法中使用with,因为它太多了。您需要:1) 创建另一个Enter()实例,2) 手动调用其__enter__(),3) 将其__exit__保存在实例变量中,以便您可以在__exit__()中调用它。跨度>
标签: python macros contextmanager