python函数式生成器的简单介绍( 三 )


sum(x ** 2 for x in xrange(4))
而不用多此一举的先构造一个列表:
sum([x ** 2 for x in xrange(4)])
2.3 再看生成器
前面已经对生成器有了感性的认识 , 我们以生成器函数为例 , 再来深入探讨一下Python的生成器:
1. 语法上和函数类似:生成器函数和常规函数几乎是一样的 。它们都是使用def语句进行定义,差别在
于,生成器使用yield语句返回一个值 , 而常规函数使用return语句返回一个值
2. 自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for
循环 , sum函数) 。由于生成器自动实现了迭代器协议 , 所以 , 我们可以调用它的next方法,并且 , 
在没有值可以返回的时候,生成器自动产生StopIteration异常
3. 状态挂起:生成器使用yield语句返回一个值 。yield语句挂起该生成器函数的状态 , 保留足够的信息,
以便之后从它离开的地方继续执行
3. 示例
我们再来看两个生成器的例子,以便大家更好的理解生成器的作用 。
首先 , 生成器的好处是延迟计算,一次返回一个结果 。也就是说,它不会一次生成所有的结果,这对于大
数据量处理,将会非常有用 。
大家可以在自己电脑上试试下面两个表达式,并且观察内存占用情况 。对于前一个表达式,我在自己的电
脑上进行测试,还没有看到最终结果电脑就已经卡死,对于后一个表达式,几乎没有什么内存占用 。
sum([i for i in xrange(10000000000)])
sum(i for i in xrange(10000000000))
除了延迟计算,生成器还能有效提高代码可读性 。例如 , 现在有一个需求,求一段文字中,每个单词出现
的位置 。
不使用生成器的情况:
def index_words(text):
result = []
if text:
result.append(0)
for index, letter in enumerate(text, 1):
if letter == ' ':
result.append(index)
return result
使用生成器的情况:
2017/11/6 如何更好地理解Python迭代器和生成器? - 知乎
4/5
def index_words(text):
if text:
yield 0
for index, letter in enumerate(text, 1):
if letter == ' ':
yield index
这里 , 至少有两个充分的理由说明 ,使用生成器比不使用生成器代码更加清晰:
1. 使用生成器以后,代码行数更少 。大家要记?。绻氚汛胄吹腜ythonic , 在保证代码可读性的前
提下,代码行数越少越好
2. 不使用生成器的时候,对于每次结果,我们首先看到的是result.append(index),其次,才是index 。
也就是说,我们每次看到的是一个列表的append操作,只是append的是我们想要的结果 。使用生成
器的时候,直接yield index , 少了列表append操作的干扰,我们一眼就能够看出,代码是要返回
index 。
这个例子充分说明了,合理使用生成器 , 能够有效提高代码可读性 。只要大家完全接受了生成器的概念,
理解了yield语句和return语句一样 , 也是返回一个值 。那么,就能够理解为什么使用生成器比不使用生成
器要好,能够理解使用生成器真的可以让代码变得清晰易懂 。
4. 使用生成器的注意事项
相信通过这篇文章,大家已经能够理解生成器的作用和好处 。但是,还没有结束,使用生成器,也有一点
注意事项 。
我们直接来看例子 , 假设文件中保存了每个省份的人口总数,现在 , 需要求每个省份的人口占全国总人口

推荐阅读