理解__getattr__, __setattr__

"yield" in recursive generator

simplyzhao posted @ 2009年8月05日 00:46 in Python , 2914 阅读

来源: www.javaeye.com/topic/338111

 

二叉树的中序遍历,递归的genertor(想当然的解法,和遍历二叉树的算法完全一样)

  1. class tree_t:  
  2.     def __init__(self, data, left = None, right = None):  
  3.         self.left = left  
  4.         self.data = data  
  5.         self.right = right  
  6.   
  7. left = tree_t("left")  
  8. right = tree_t("right")  
  9. root = tree_t("root", left, right)  
  10.   
  11. def infix_iterate(tree):  
  12.     if tree.left:  
  13.         infix_iterate(tree.left)  
  14.     yield tree  
  15.     if tree.right:  
  16.         infix_iterate(tree.right)  
  17.   
  18. for tree in infix_iterate(root):  
  19.     print tree.data



二叉树的中序遍历,递归的genertor(正确的解法)

  1. class tree_t:  
  2.     def __init__(self, data, left = None, right = None):  
  3.         self.left = left  
  4.         self.data = data  
  5.         self.right = right  
  6.   
  7. left = tree_t("left")  
  8. right = tree_t("right")  
  9. root = tree_t("root", left, right)  
  10.   
  11. def infix_iterate(tree):  
  12.     if tree.left:  
  13.         for child in infix_iterate(tree.left):  
  14.             yield child  
  15.     yield tree  
  16.     if tree.right:  
  17.         for child in infix_iterate(tree.right):  
  18.             yield child  
  19.   
  20. for tree in infix_iterate(root):  
  21.     print tree.data



第1个例子没有任何问题,很直观。但在第2个例子时,发现程序只输出一行代码root,仔细看了下参考资料,才注意到正确的递归调用和我想当然的不一样:

  1. 想当然的写法:  
  2. if tree.left:  
  3.     infix_iterate(tree.left)  
  4.   
  5. 正确的写法:  
  6. if tree.left:  
  7.     for child in infix_iterate(tree.left):  
  8.         yield child  


不知道为什么python的递归generator没有采用例子2中那样直观的写法?是实现困难的原因吗?

 

 

Python里带有yield表达式(*)的函数是generator function,而调用一个generator function总是返回一个iterator;iterator不调用其next()方法是不会执行的;iterator总是通过yield表达式来提供next()方法的返回值,自然,谁调用next()方法谁就会获得返回值。

在 楼主的第二种写法里,那两个if语句里的调用并不是“递归调用”,而只是单纯的获得了两个iterator,并且没有让它们执行;generator function要真的“递归”起来,就得像第三种写法那样,在generator function的函数体里获得了一个iterator之后,遍历这个iterator里的值并逐个yield返回出去。for...in语句所做的正好就是拿到一个iterable然后逐个遍历里面的值,所以正好适合用在这个场景。

要是直接带第二种写法上加点东西就能看到得到的iterator里发生的事:

Python代码
  1. class tree_t:  
  2.     def __init__(self, data, left = None, right = None):  
  3.         self.left = left  
  4.         self.data = data  
  5.         self.right = right  
  6.   
  7. left = tree_t("left")  
  8. right = tree_t("right")  
  9. root = tree_t("root", left, right)  
  10.   
  11. def infix_iterate(tree):  
  12.     if tree.left:  
  13.         print (infix_iterate(tree.left).next().data)  
  14.     yield tree  
  15.     if tree.right:  
  16.         print (infix_iterate(tree.right).next().data)  
  17.   
  18. for tree in infix_iterate(root):  
  19.     print tree.data  


当然这样不能用于遍历就是了,只是用来说明generator function里调用了“自己”得到的是什么。

 

 

Enjoy Linux, Fighting.

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter