Python高级-生成器

生成器可以认为是一个特殊的迭代器,用途也是对特定数据序列进行逐个遍历,只不过生成器是 Python 在平台层面实现了通用的迭代器逻辑,在编码时开发者只需要通过 yield 关键字即可快速构建迭代器,符合 Python 简洁的风格。

Python高级-迭代器 一文中通过迭代器实现了逐个遍历一个英文句子中的单词的例子

如下是通过生成器实现的简洁版本:

import re
import reprlib

RE_WORD = re.compile(r'\w+')


class Sentence:

    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text)

    def __iter__(self):
        for word in self.words:
            yield word

s = Sentence('"The time has come," the Walrus said')
for word in s:
    print(word)

生成器的核心原理如下:

  • 在函数中存在 yield 关键字,则该函数会被底层认为是一个生成器函数,调用该函数会返回一个生成器对象
  • 生成器与迭代器在使用上没有差别,都可以通过 for 循环或者 next() 函数进行迭代
  • 程序在执行到 yield 关键字后会暂停函数(保留上下文),并返回 yield 后的变量值,在下一次迭代动作触发后继续执行,直到函数所有代码执行完毕后会自动抛出 StopIteration 异常作为迭代结束的信号

同时生成器还具备惰性加载的特性,在处理海量数据时,对于节省内存非常有效。

惰性加载允许程序运行过程中按需,分批地加载数据资源,在之前实现的代码中并没有利用这个特性,在 Sentence 对象初始化阶段就完成了全量单词列表的构建(想象一下,如果这个单词列表的数据巨大很有可能就把内存撑爆了)。

如下是一个惰性生成器实现版本:按需去逐个匹配句子中的单词,这也依赖于 RE_WORD.finditer(self.text) 支持返回一个迭代器

# 惰性生成器
import re
import reprlib

RE_WORD = re.compile(r'\w+')


class Sentence:

    def __init__(self, text):
        self.text = text
    def __repr__(self):
        return f'Sentence({reprlib.repr(self.text)})'

    def __iter__(self):
        for match in RE_WORD.finditer(self.text):
            yield match.group()

s = Sentence('"The time has come," the Walrus said')
for word in s:
    print(word)