2017-06-15 59 views
0

我最近在一个算法中列出了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 
+1

向我们显示完整的确切错误消息。 – user2357112

+0

+您的代码是如何被调用的 - 所以我们可以重新编写 – alfasin

+0

@ user2357112这就是要点,没有错误,生成器似乎处理它。 – XanX3601

回答

3

D.outgoing_edge_iterator(source).next()产生一个例外,肯定,但例外的是StopIteration。这是用来表示迭代器结束的异常,当它从您的生成器传播出去并到达上面的for循环时,for循环将它表示循环完成。

在更新的Python版本中,此行为为changed;在发电机内部升起的StopIteration现在将被转换为RuntimeError

+0

哦!好 !那么可以假设它会保持这种状态,这是一个好办法吗?删除这个“if”使得所有的算法更快 – XanX3601

+0

@ XanX3601:我看不到你的整个算法,但是在我看来,去掉这个条件会让你的算法错误;它看起来像是如果您删除该条件,您的算法可能会开始生成断开的子图而不是生成树。 – user2357112

+0

Sage已经包含[生成树生成函数](http://doc.sagemath.org/html/en/reference/graphs/sage/graphs/graph.html#sage.graphs.graph.Graph.spanning_trees),所以你可以使用它。如果你特别需要一个迭代器(Sage的函数产生一个列表),将代码从Sage的代码中提取出来可能是一个很好的解决方法。 – user2357112