【发布时间】:2017-11-18 14:01:47
【问题描述】:
我最近研究了一种算法,用于在 Sagemath 的有向图中列出生成树。
这样做,我和我的同事发现了一种我们并不完全理解的奇怪行为。
在规范方面,Sagemath 使用 Python 2.7 和 import absolute import from __future__。
该算法使用“yield”关键字一一列出生成树,并对其自身进行递归调用。 在某一时刻,我们会在递归调用之前进行测试,以确保它不会触发错误。
但是,如果我们删除测试并让算法生成错误而不捕获它,生成器不会自行停止而是传递到下一个递归调用。
如果我可以给出一个图解的解释,假设每个递归调用有 3 个步骤,我们得到了这样的结果:
- 0 级 - 步骤 1
- 0 级 - 步骤 2
- 1 级 - 步骤 1
- 级别 1 - 步骤 2
- level 2 - step 1
- 级别 1 - 步骤 3
- 第 2 级 - 第 1 步
- 2 级 - 产量 -level 0 - 第 3 步
- ...
如果我们使用“try catch”捕获错误,那么算法将自行停止。
我把代码放在这里;如果您不了解 Sagemath,我不确定您是否能掌握所有内容,但其中大部分是可以理解的。我会做出具体的评论以突出显示有趣的部分并删除代码的某些部分。
我希望有人可以向我解释这种行为;就像生成器对象可以在递归调用期间处理异常并在生成时忽略它们。
def _rec_spanning_trees():
if len(list_merged_edges) == self.order()-1: # CONDITION TO YIELD
for indexes in product(*list_merged_edges):
yield DiGraph([list_edges[index] for index in indexes], format='list_of_edges', pos=self.get_pos())
# part removed
# THIS HERE !
# "outgoing_edge_iterator" is raising an error if D does not have any edges
s, x, l = D.outgoing_edge_iterator(source).next()
# HERE !
# If I remove the "if(len(...." then the line above will raise an error sometime, but do not if I let it
D.delete_edge(s, x, l)
if len(list(D.depth_first_search(source))) == D.order():
for tree in _rec_spanning_trees():
yield tree
D.add_edge(s, x, l)
# part removed
for tree in _rec_spanning_trees():
yield tree
# part removed
【问题讨论】:
-
向我们展示完整、准确的错误信息。
-
+ 你的代码是如何被调用的——所以我们将能够重现
-
@user2357112 这就是重点,没有错误,生成器似乎可以处理它。
-
@alfasin 这段代码是一个类方法的实习函数,但 user2357112 给出的答案似乎相当不错
标签: python recursion generator