yield是弄啥玩意的?
在介绍yield之前,先有必要看看列表生成式。
在Python中生成一个1-5的列表,可以用range(1,6)或者 xrange(1,6)。
In[5]: for i in xrange(1,6):
... print i
...
1
2
3
4
5
或
In[6]: range(1,6)
Out[6]: [1, 2, 3, 4, 5]
那么问题来了,如果要生成1*2,2*2,3*2....n*2这样的列表 该如何做呢?可以先用for循环试试。
In[7]: l_test = []
In[8]: for i in range(1,6):
... l_test.append(i*2)
...
In[9]: l_test
Out[9]: [2, 4, 6, 8, 10]
这样写虽然达到了我们的目的,但是这样的循环很繁琐,又要声明列表,又要append,而列表生成式可以一句代码搞定。
In[11]: [i*2 for i in range(1,6)]
Out[11]: [2, 4, 6, 8, 10]
是不是so easy?,这就是最简单的一种列表生成式。
虽然列表生成式 相对于 循环来说已经很大程度上解放生产力了,但是当列表元素上百万的时候,我们PC的内存是hold不住的,况且大多数情况可能我们创建了一个上百万个元素的列表 ,而我们真正需要的只要前面几个,这是一种极大地内存浪费。生成器(generator)就是解决这种问题的。
上面我们创建迭代器的时候 是用的[] ,而生成器虽然也是迭代器的一种,但是却用()符号。
In[12]: list1 = [x*2 for x in range(1,6)]
In[13]: list1
Out[13]: [2, 4, 6, 8, 10]
In[14]: generator = (x*2 for x in range(1,6))
In[15]: generator
Out[15]: at 0x0000000003A265E8>
在执行后 list1返回的是列表,而generator返回的是一个生成器,那么如何访问生成器中的元素呢?这里使用.next()方法
In[16]: generator.next()
Out[16]: 2
In[17]: generator.next()
Out[17]: 4
In[18]: generator.next()
Out[18]: 6
In[19]: generator.next()
Out[19]: 8
In[20]: generator.next()
Out[20]: 10
In[21]:
In[21]: generator.next()
Traceback (most recent call last):
File "D:\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py", line 3066, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "", line 1, in
generator.next()
StopIteration
当 生成器中的元素被访问完毕后,会抛出StopIteration异常。
也就是说,generator保存的是一种计算方法,可以使用next()来访问其中的元素。
讲了这么多,到底和yield关键字有什么半毛线关系呢?别急,来看一个例子,如果我想输出 ’I‘,’love‘,’Python‘这三个string,我想每次只输出一个string,而不是一次性都输出,怎么做呢?
In[23]: def printStr():
... print u'第一个字符'
... yield "i"
... print u'第二个字符'
... yield "love"
... print u'第三个字符'
... yield "Python"
...
In[24]: p = printStr()
In[25]: p.next()
第一个字符
Out[25]: 'i'
In[26]: p.next()
第二个字符
Out[26]: 'love'
In[27]: p.next()
第三个字符
Out[27]: 'Python'
很明显 printStr不是一般意义上的函数,而是一个生成器,在执行的过程中,执行到yield时就会暂停,再次执行就会从前一次执行停止的地方开始。
生成器也是会结束的,从上面的例子看到,当执行到最后一行语句时就是generator结束的标志。
微信: