我最近在一个算法中列出了Sagemath的二叉树上的生成树。奇怪的行为Python生成器的递归性
这样做,我的同事和我发现了一个我们并不完全了解的奇怪行为。
对于规范方面,Sagemath使用Python 2.7和import absolute import from __future__
。
算法使用带有递归调用的“yield”关键字逐个列出生成树。 一次,我们在递归调用之前进行测试,以确保它不会触发错误。但是,如果我们删除测试并让算法生成一个错误,而不捕获它,那么生成器不会自行停止,而是会传递给下一个递归调用。
如果我可以给一本图文并茂的解释,让我们说有一个在每次递归调用3个步骤,我们得到了这样的事情:
- 0级 - 第1步
- 0级 - 第2步
- 级别1 - 步骤1
- 1级 - 第2步
- 2水平 - 步骤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这就是要点,没有错误,生成器似乎处理它。 – XanX3601