第16條 考慮用生成器來改寫直接返回列表的函數

前面提到,對於數據量很大時,可以用生成器表達式代替列表推導,同樣,當一個函數返回列表且數據量很大時,應該考慮使用生成器。
案例1:獲取字符串中每個單詞的首字母

def index_words(text):
    result = []
    if text:
        result.append(0)
    for index,letter in enumerate(text):
        if letter == ' ':
            result.append(index+1)
    return result
if __name__ == "__main__":
    text = "Four score and seven years ago..."
    result = index_words(text)
    print(result)

上面的函數,在返回前,將所有的結果存放到result列表中。如果文本輸入量很大,就會導致程序耗盡內存並崩潰。如果使用生成器,則可以應對任意長度的輸入數據。

生成器是使用yield表達式的函數

  • 調用生成器函數時,它並不會真的運行,而是會返回迭代器。每次在迭代器上面調用next函數,迭代器會把生成器推進到下一個yield表達式那裏。
  • 生成器調用yield的每一個值,都會由迭代器返回給調用者。
  • 無論輸入量多大,生成器產生一系列輸出,都不會影響執行時所消耗的內存。

利用生成器改寫的上述函數爲:

def index_words(text):
    if text:
        yield 0
    for index,letter in enumerate(text):
        if letter == " ":
            yield index+1
if __name__ == "__main__":
    text = "Four score and seven years ago..."
    it = index_words(text) # 迭代器
    result = list(it)
    print(result)

定義這種生成器函數的時候,唯一需要注意的就是:函數返回的那個迭代器,是有狀態的,調用者不應該反覆使用它。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章