转载请注明出处:https://www.jianshu.com/u/5e6f798c903a
[^*] 表示注脚,在文末可以查看对应连接,但简书不支持该语法。
generator [^4] [^7] [^9]
本质上来说,生成器(generator)就是一个函数,它提供了一种实现迭代器协议的便捷方式。生成器与普通函数的区别在于它包含 yield
表达式,并且不需要定义 __iter__()
和__next__()
。也就是说,使用 yield
语句的函数或方法便可被称为生成器函数( generator function )。关于 yield
可参考 The yield statement 和 the documentation for the yield expression.
# 一个生成器函数的示例:def generator_func(): cont = 0 while cont < 3: cont += 1 yield cont
generator 在官方文档的语境中存在如下两种含义:
第一种用于指代生成器函数,本文内容均采用这种含义
第二种是用于指代 generator iterator(下一节将介绍此概念)。比如通过下面的代码可以看到 Python 将生成器函数描述为函数类型,但将 generator iterator 描述为 Generator 类型。因此,当我们在文档中遇到 generator 时,一定要根据上下文来判断其具体所指的对象。
# 关于生成器在不同语境中的含义:from collections import abcimport typesdef generator_func(): cont = 0 while cont < 3: cont += 1 yield cont g_iterator = generator_func()assert isinstance(generator_func, types.FunctionType) # 无异常assert isinstance(g_iterator, abc.Generator) # 无异常
1. generator iterator
generator-iterator 是通过生成器函数创建的实例对象 (下文中简称为 g_iterator),该对象支持 __iter__()
和 __next__()
方法,属于迭代器。g_iterator 适用于任何需要迭代器的场景。注意,通过生成器函数创建 g_iterator 时,并不会执行生成器函数体中的任何代码:
def generator_func(): print("生成器函数") cont = 0 while cont < 3: cont += 1 yield cont g_iterator = generator_func()# 不会打印"生成器函数"
细节上来讲,g_iterator 用于执行函数体:通过调用 g_iterator.__next__()
方法,可继续执行函数体。如果在执行过程中遇到了 yield
语句,便会暂停执行并返回指定变量;如果在遇到 return
语句或者函数体已执行完毕时,便会抛出 StopIteration
,表明 g_iterator 对象已被耗尽。
简单来说,yield
用于暂停 g_iterator 的执行,并会记住当前位置的执行状态(包括局部变量和待处理的 try 语句)。当 g_iterator 恢复执行时,便会从之前中断的位置开始执行(普通函数每次调用时,都会从头开始重新执行)
如果将 g_iterator 对象传递给 iter()
,只会返回指向 g_iterator 自身的引用,并不会创建具备新id的迭代器对象。
class Generator: def __iter__(self):#生成器函数 cont = 0 while cont < 3: cont += 1 yield cont a_generator = Generator()# 通过同一个generator可创建不同的generator iterator。# 例如g_iter1和g_iter2是两个具备不同标识符id的generator iteratorg_iter1 = iter(a_generator) g_iter2 = a_generator.__iter__() print("g_iter1的id是:{0}, 类型是:{1}".format(id(g_iter1), type(g_iter1))) print("g_iter2的id是:{0}, 类型是:{1}\n".format(id(g_iter2), type(g_iter2)))# 对同一个generator iterator依次执行这两种方法,均返回带有同一id的对象print(id(g_iter1.__iter__())) print(id(iter(g_iter1)))"""输出: g_iter1的id是:2742184172272, 类型是:<class 'generator'> g_iter2的id是:2742184172624, 类型是:<class 'generator'> 2742184172272 2742184172272 """
2. 生成器表达式
generator expression[^4]
该表达式同样会返回一个 generator iterator。该表达式与常规表达式一样,会使用 for
循环来定义一个循环变量 i
及其范围;也可使用 if
对 i
进行筛选。该组合表达式可为封闭(enclosing)函数生成值:
sum(i*i for i in range(10)) # sum of squares 0, 1, 4, ... 81; result 285
2.1 对比其他常规表达式
列表推导式用于构建一个列表:
>>> numbers = [1, 2, 3, 4, 5, 6]>>> [x * x for x in numbers] [1, 4, 9, 16, 25, 36]
集合推导式用于构建一个集合:
>>> {x * x for x in numbers} {1, 4, 36, 9, 16, 25}
字典推导式用于构建一个字典:
>>> {x: x * x for x in numbers} {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}
注意,没有元组推导式,元括弧用于创建生成器表达式:
>>> lazy_squares = (x * x for x in numbers)>>> lazy_squares <generator object <genexpr> at 0x10d1f5510>>>> next(lazy_squares)1>>> list(lazy_squares) [4, 9, 16, 25, 36]
注脚:
[1] 语言参考 - 3.1. Objects, values and types
[2] 标准库 8.4. collections.abc
— Abstract Base Classes for Containers
[3] Iterables vs. Iterators vs. Generators | 完全理解 Python 迭代对象、迭代器、生成器
[4] Glossary 术语表
[5] iter(object[, sentinel])
[6] 语言参考 - 8.3. The for
statement
[7] 标准库 - 4.5. terator Types
[8] 语言参考 - 3.3.7. Emulating container types
[9] 语言参考 -3.2. The standard type hierarchy