Python中的yield

Python中的yield

其实一开始并不想学这个用法。可是随着教材往下看,老是能碰到yield这个东西,致使什么都看不下去。神烦的不行。因而专门拿出来啃一下html

http://pyzh.readthedocs.org/en/latest/the-python-yield-keyword-explained.html python

这是一篇从stackflow翻译过来的答案, 很好的解释了yield。虽是中文,不过我看的时候仍是很吃力的,初学者都这样吧........哎.......编程

逻辑上来看,想弄懂yield就要懂生成器generator,想懂generator就要懂迭代iteration。ide

(不行,我要吐槽一下,好多网上搜到的资料都是给有必定编程基础的人写的,解释一个命令,就会带出另一个没见过的命令或者概念,嵌套嵌套再嵌套,没完没了。。。举例:原本想查一下enumerate的用法,结果碰到yield,查yield,结果碰到xrange,更别提遇到各类带下划线的奇怪函数....真是够了 嗷嗷嗷)函数

吐槽归吐槽,继续硬着头皮学吧。。。post

 

---------------------------------------------------------------------------------------------------------------------ui

注意:如下内容是上面连接的解释版。若是看了连接能够不看这段spa

 

[python]  view plain  copy
 
  1. mylist = [x*x for x in range(3)]  
  2. print mylist  
  3. mygen=(x*x for x in range(3))  
  4. print mygen  

 

 

代码解释.net

行1生成一个列表list,这个列表的每一个元素由x的平方组成,x的取值为range(3),也就是0,1,2。所以这个列表有三个元素:0的平方(0),1的平方(1),2的平方(4)。翻译

行2打印出这个列表的内容,显示结果果然是[0,1,4]

行3生成的是一个生成器generator,它和行1惟一的不一样就是它用的小括号。可是产生的返回值并再也不是一个列表了。那是什么呢?

行4想要打印出来这个mygen生成器,但结果显示是这样的: <generator object <genexpr> at 0x022F8030> 一个内存地址。

 

怎么理解这个生成器的概念呢?如上例子所示,其实这个mygen生成器就是用来生成x的平方的东西。这个结果呢就存在上面显示的内存地址里。可是因为你还没说你到底要谁的平方,因此只能看到个地址不能看到答案。mylist则不一样,它是把全部答案穷举列在内存里了,你须要哪一个就从里面找出来便可,比较耗费资源。而mygen则还没生成,你须要哪一个我现制造一个出来放在一个内存空间显示,节省了资源。(好吧这一段都是我本身的理解....教科书尚未看....)

 

辣么,怎么用这个生成器涅?举例

 

[python]  view plain  copy
 
  1. mygen=(x*x for x in range(3))  
  2. for i in mygen:  
  3.     print (i)  


这样就能够把mygen能够生成的全部平方数拿出来了。结果显示:

 

0

1

4

注意,答案是一个一个蹦出来的,就好像循环读取同样。辣么,当你须要循环读取、而不是一会儿全显示出来的时候,用生成器是最好不过的了。

---------------------------------------------------------------------------------------------------------------

若是看上一段内容仍是比较困难的话,咱们再来看下面这段。我找了个新guide,可见: www.cnpythoner.com/post/298.html

---"在python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器" (也就是说,只要有yield这个词出现,你在用def定义函数的时候,系统默认这就不是一个函数啦,是一个生成器啦!!无论里面内容你写成神马样子 )

--- 通常def定义的函数,都会return一个返回值。而def定义的生成器,返回的则是一个对象,也就是上面提到的相似于“内存地址”的东西。(看来我上面解释的还不是很对)

--- 若是须要生成器返回(下一个)值,须要调用.next()函数。其实当系统判断def是生成器时,就会自动支持.next()函数

 

[python]  view plain  copy
 
  1. c = h() #h()包含了yield关键字    
  2. print  c.next() #返回值   

 

----------------------------------------------------------------------------------------------------------------

辣么,咱们来作一个小小的习题,看看是否理解了yield

----------------------------------------------------------------------------------------------------------------

 

[python]  view plain  copy
 
  1. def fib(max):  
  2.     a, b = 1, 1  
  3.     while a < max:  
  4.         yield a  
  5.         a, b = b, a+b  
  6.   
  7. for n in fib(15):  
  8.     print n  
  9.   
  10. m = fib(13)  
  11. print m  
  12. print m.next()  
  13. print m.next()  
  14. print m.next()  


以上是一段关于斐波那契数列的程序。

fib()函数由于含有yield,被系统默认为是一个生成器。

for语句调用了fib(15)。当max=15时,进入fib()生成器,执行到yield a, 返回a值以及整个生成器暂停的状态,将a值赋给n, 打印出来;由于是for语句循环,因此又回到fib(15)语句,因为是生成器,所以从上次截断的位置开始执行,b值赋给a, a+b值赋给b,又由于是while语句,则继续while循环,yield a值,循环暂停跳出返回a值及生成器状态,把a值赋给n, 打印n。如此往复,一直循环到15结束。

m被赋了fib(13)这个生成器,每一次执行m.next()函数就会打印下一个值。

从上面的分析过程,咱们看一下运行结果:

 

注意:

1. 每一个生成器只能使用一次。好比上个例子中的m生成器,一旦打印完m的6个值,就没有办法再打印m的值了,由于已经吐完了。

2. yield通常都在def生成器定义中搭配一些循环语句使用,好比for或者while,以防止运行到生成器末尾跳出生成器函数,就不能再yield了。有时候,为了保证生成器函数永远也不会执行到函数末尾,会用while True: 语句,这样就会保证只要使用next(),这个生成器就会生成一个值,是处理无穷序列的常见方法。

相关文章
相关标签/搜索