在Python中从块内停止生成器

2024-05-28 20:30:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个生成器,它从有向无环图(DAG)生成节点,深度优先:

def depth_first_search(self):
    yield self, 0 # root
    for child in self.get_child_nodes():
        for node, depth in child.depth_first_search():
            yield node, depth+1

我可以像这样遍历节点

for node, depth in graph.depth_first_search():
    # do something

我希望能够从for循环中告诉生成器,如果满足某些条件,就不要再深入到图中。

我提出了下面的解决方案,即使用外部函数。

def depth_first_search(self, stop_crit=lambda n,d: False):
    yield self, 0 # root
    for child in self.get_child_nodes():
        for node, depth in child.depth_first_search():
            yield node, depth+1
            if stop_crit(node, depth): break

这个解决方案迫使我在定义stop-crit之前声明所需的变量,以便可以从中访问它们。

在Ruby中,yield返回块中的最后一个表达式,因此可以方便地使用它来告诉生成器继续或停止。

在Python中实现此功能的最佳方法是什么?


Tags: inselfnodechildforsearchget节点
3条回答

天真的解决方案:

def depth_first_search(self):
    yield self, 0 # root
    for child in self.get_child_nodes():
        for node, depth in child.depth_first_search():
            if(yield node, depth+1):
                yield None # for .send
                return

您可以正常调用它,但必须保存iterable才能中止:

it = graph.depth_first_search()
for node, depth in it: #this is why there should be pronouns for loop iterables
    stuff(node,depth)
    if quit: it.send(1) 
    # it.next() should raise StopIteration on the next for iteration

我想现在可以了。

通常情况下,您不会告诉iterable检查条件,而是在循环的主体中执行此操作:

for node, depth in graph.depth_first_search():
    if node meets condition:
        # do something with node 
        break
# do something with node, its still referencing what you breaked on

这段代码的优点是不会让任何人感到惊讶或困惑。

通常在Python中,您只需停止使用生成器,然后忘记它。要点。(这样就按照通常的方式把东西留给了垃圾收集器)

然而,通过使用generator.close(),您可以强制立即执行生成器清理,从而立即触发所有终结。

示例:

>>> def gen():
...     try: 
...         for i in range(10):
...             yield i
...     finally:
...         print "gen cleanup"
...         
>>> g = gen()
>>> next(g)
0
>>> for x in g:
...     print x
...     if x > 3:
...         g.close()
...         break
...        
1
2
3
4
gen cleanup
>>> g = gen()
>>> h = g
>>> next(g)
0
>>> del g
>>> del h   # last reference to generator code frame gets lost
gen cleanup

相关问题 更多 >

    热门问题