_
考虑以下示例:
def generator(iterable):
print('Start')
for item in iterable: yield item
print('Stop')
for x in generator(range(10)):
print(x)
if x==3: break
print(x)
,其输出为
Start
0
0
1
1
2
2
3
Python当然会完全按照它所说的去做。在x == 3之后不再调用生成器,因此永远不会打印“停止”。生成器抽象是合理的。然而,在这种情况下,我实际上试图实现一种微妙的不同类型的抽象,有点像装饰循环以使其成为自定义循环。有些代码应该在循环之前运行,一些代码用于每次迭代,一些代码应该在循环之后运行,即使在break
的情况下也是如此。
当然,我不依赖于这种确切的抽象来使我的程序工作,但它会很好。有没有人对这个案子有任何好的想法?
亲切的问候。
答案 0 :(得分:4)
生成器是循环的良好抽象,但对于前后代码,Python有另一个抽象 - 上下文管理器和'with'语句。您可以将这两者结合使用,例如:这样:
class generator_context:
def __init__(self, iterable):
self.iterable = iterable
def __enter__(self):
print('Start')
for item in self.iterable: yield item
def __exit__(self, e_type, e_value, e_traceback):
if e_type is None:
print('Stop')
with generator_context(range(10)) as generator:
for x in generator:
print(x)
if x==3: break
print(x)
答案 1 :(得分:3)
好吧,你可以试试看你的发电机>最后。
def generator(iterable):
try:
print('Start')
for item in iterable: yield item
finally:
print('Stop')
这使得内部最终总是执行。
答案 2 :(得分:1)
正如我在评论中提到的,上下文管理器可能会做你想要的。这是一个自动关闭生成器的方法(这是有意义的,因为"stop"
被打印为表示没有更多的值)。
class my_generator:
def __init__(self, iterable):
self.g = (x for x in iterable)
def __iter__(self):
return self.g
def __enter__(self):
print('start')
return self
def __exit__(self, exc_type, exc_value, trace):
self.g.close()
# do whatever cleanup is necessary in case of exception
print('stop')
用法:
>>> with my_generator([1,2,3]) as g:
... for x in g:
... print(x)
... if x == 2:
... break
...
start
1
2
stop
>>> list(g)
[]