第16条:考虑用生成器来改写直接返回列表的函数
如果一个函数要产生一系列结果,最简单的做法是把这一系列结果放在一个列表里,然后返回列表。
但是这里有个问题,如果我们产生的结果特别多,比如读取一个很大的文件的所有行,这时就很容易造成内存异常。
所以,正常情况下,我们不会去使用一个列表去存储这种占内存特别多的一系列结果,而是采用一种可以不断获取数据的方法来实现,这就是之前说到的生成器。
先看例子:
def index_words(text):
result = []
if text:
result.append(0)
for index, letter in enumerate(text):
if letter == ' ':
result.append(index + 1)
return result
这个是一个从字符串中取出每个单词首字母位置的例子,运行看下效果:
address = 'Four score and seven years ago...'
result = index_words(address)
print(result[:3])
>>>
[0, 5, 11]
可以看出上面的方法可以完成要求,但是代码稍显冗余,将近一般的代码用来实现 result 的 append 上面,而现在的重点是获取首字母位置,如果用生成器来实现的话,可以这样:
def index_words_iter(text):
if text:
yield 0
for index, letter in enumerate(text):
if letter == ' ':
yield index + 1
result = list(index_words_iter(address))
print(result[:3])
>>>
[0, 5, 11]
换成生成器后,就完全省去了 result 的 append 相关代码,而且,目的很清晰,就是获取每个单词的首字母位置。这里的重点是 yield 表达式,它会在函数运行的时候返回迭代器,每次调用迭代器后,会推到下一次的 yield 位置,然后由迭代器返回 yield 返回的值。这样如果传入的字符串是由一个很大的文本文件读出来的,就不用担心占用太多的内存。