Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1868216
  • 博文数量: 152
  • 博客积分: 3730
  • 博客等级: 上尉
  • 技术积分: 3710
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-02 14:36
个人简介

减肥,运动,学习,进步...

文章分类

全部博文(152)

文章存档

2016年(14)

2015年(17)

2014年(16)

2013年(4)

2012年(66)

2011年(35)

分类: Python/Ruby

2012-07-13 16:55:51

前面快速的学习了Python的基本操作,但是还是存在很多的问题,在特别是一些小的知识点很少关注,但是有非常的好用,yield是Python中比较有意思,也比较有难度,我也是阅读代码的过程中发现了这个函数的好处,yield是生成的意思,但是在python中则是作为生成器理解,生成器的用处主要可以迭代,这样简化了很多运算模型。
关于yield可以参看《Python 深入理解yield》这篇文章中比较详细的描述了yield的基本原理和问题。
yield在python2.5以后不再是一个句子,而是一个表达式,表达式是有返回值的,就如同我们在C语言中的if(expression)一样。
当函数中存在yield以后,那么该函数就不在是普通的函数了,而是一个生成器。当该函数被调用时,并不会自动执行,而是暂停中,可以从下面的代码中得到体现。

点击(此处)折叠或打开

  1. >>> def mygenerator():
  2. ... print 'start....'
  3. ... yield 5
  4. ...
  5. >>> mygenerator()
  6. <generator object mygenerator at 0xa2084b4>
从上面的结果可以知道,在mygenerator()之后,并没有打印出starting....说明存在yield的函数被调用的时候是没有运行的,可以认为是暂停的状态,因此需要重新启动程序。这时采用next()即可实现函数的启动。

点击(此处)折叠或打开

  1. >>> g = mygenerator()
  2. >>> g.next()
  3. start....
  4. 5
  5. >>> g.next()
  6. Traceback (most recent call last):
  7.   File "", line 1, in <module>
  8. StopIteration
mygenerator()中创建了对象g,这时需要next()启动程序的运行,出现了上面的结果,也就是完成了程序的重新运行,但是遇到yield后就会再次停止,从上面的效果我们可以知道,在第一次运行g.next()之后,打印,然后遇到了yield 5,这时候就会停止,再次g.next()之后,后面没有yield,说明迭代过程结束,抛出了StopIteration异常。

点击(此处)折叠或打开

  1. >>> def mygenerator2():
  2. ... print 'starting ....'
  3. ... yield 5
  4. ... print 'middle ....'
  5. ... yield 12
  6. ... print 'end ....'
  7. ...
  8. >>> g1 = mygenerator2()
  9. >>> g1.next()
  10. starting ....
  11. 5
  12. >>> g1.next()
  13. middle ....
  14. 12
  15. >>> g1.next()
  16. end ....
  17. Traceback (most recent call last):
  18.   File "", line 1, in <module>
  19. StopIteration
上面的代码也说明我的分析是正确的,第一次调用next()就执行到yield 5,暂停,然后next(),重新启动,并执行到yield 12,然后再次next()之后就会抛出错误,从上面打印出来的字符串就可知道。但输出中我们还发现了5,12等这是为什么呢?我认为这实质上是yield 5的返回值,因为表达式也会存在值的问题,这是肯定会输出表达式的值。
 
那么这是否可以认为yield 5的返回值一定是5吗?实际上并不是这样,这个与send函数存在一定的关系,这个函数实质上与next()是相似的,区别是send是传递yield表达式的值进去,而next不能传递特定的值,只能传递None进去,因此可以认为g.next()和g.send(None)是相同的。

点击(此处)折叠或打开

  1. >>> def mygenerator2():
  2. ... print 'starting ....'
  3. ... m = yield 5
  4. ... print m
  5. ... print 'middle ....'
  6. ... d = yield 12
  7. ... print d
  8. ... print 'end ....'
  9. ...
  10. >>> g1 = mygenerator2()
  11. >>> g1.next()
  12. starting ....
  13. 5
  14. >>> g1.send('pass expression')
  15. pass expression
  16. middle ....
  17. 12
  18. >>> g1.next()
  19. None
  20. end ....
  21. Traceback (most recent call last):
  22.   File "", line 1, in <module>
  23. StopIteration
  24. >>> g1 = mygenerator2()
  25. >>> g1.next()
  26. starting ....
  27. 5
  28. >>> g1.send('pass expression')
  29. pass expression
  30. middle ....
  31. 12
  32. >>> g1.send('pass expression')
  33. pass expression
  34. end ....
  35. Traceback (most recent call last):
  36.   File "", line 1, in <module>
  37. StopIteration
从上面的效果可知道,可以知道,next()的传递的实质上就是None,而send传递进来的pass expression也作为表达式yield n的返回值,因此我们可以知道,yield的返回值并不是n的值,而是和send()传递进去的参数密切相关。实质上yield n表达式的返回值是指上就是send()函数传递进去的参数,了解到这一点是非常重要的。
 
关于send()和next()函数的返回值也是需要我们详细去分析的,从下面的代码可以知道:

点击(此处)折叠或打开

  1. >>> def returntest():
  2. ... m = yield 5
  3. ... print m
  4. ... n = yield 10
  5. ... print n
  6. ... h = yield 15
  7. ... print h
  8. ...
  9. >>> t = returntest()
  10. >>> n = t.next()
  11. >>> n
  12. 5
  13. >>> n = t.next()
  14. None
  15. >>> n
  16. 10
  17. >>> n = t.next()
  18. None
  19. >>> n
  20. 15
  21. >>> t = returntest()
  22. >>> n = t.next()
  23. >>> n
  24. 5
  25. >>> n = t.send(40)
  26. 40
  27. >>> n
  28. 10
  29. >>> n = t.send(50)
  30. 50
  31. >>> n
  32. 15
从上面的代码我们可以知道next()和send()的返回值是与yield n的n密切相关,实际上就是yield n的n值。而yield的返回值就是send()传递进来的非None参数。
 
有一段经典的代码是不得不去分析的:

点击(此处)折叠或打开

  1. >>> def addlist(alist):
  2. ... for i in alist:
  3. ... yield i + 1
  4. ...
这段代码中实际上就是运用了上面几个函数的返回值,因为for ...in句式实质上就是一个迭代器,也就是说alist[i] = addlist.next(),采用next的返回值也就是yield n的参数值n,也就是完成了alist[i] = i+1.这就是返回值的灵活运用,这段代码被灵活的运用于Python的迭代器中。
 
总结:
yield 的返回值是send(参数)中的参数,比如send(10),那么yield的返回值就是10
send(None)和next()的意思是一样的,但是因为send不能传递None量,因此这才突显出了next()函数的作用,这两个函数的返回值通常就是yield n中的参数n。
存在yield的函数不是普通的函数,而是生成器,只有调用send()或者next()函数以后才能执行,否则就是暂停的形式,这与其他函数是存在差别的。
阅读(3954) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~