[^*] 表示注脚, 在文末可以查看对应连接, 但简书不支持该语法.
generator [^4] [^7] [^9]
本质上来说, 生成器 () 就是一个函数, 它提供了一种实现迭代器协议的便捷方式. 生成器与普通函数的区别在于它包含 表达式, 并且不需要定义 __iter__()和__next__(). 也就是说, 使用 语句的函数或方法便可被称为生成器函数( 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 abc
- import types
- def 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
是通过生成器函数创建的实例对象 (下文中简称为 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__() 方法, 可继续执行函数体. 如果在执行过程中遇到了 语句, 便会暂停执行并返回指定变量; 如果在遇到 语句或者函数体已执行完毕时, 便会抛出 , 表明 g_iterator 对象已被耗尽.
简单来说, 用于暂停 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 iterator
- g_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. 该表达式与常规表达式一样, 会使用 循环来定义一个循环变量 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. - Abstract Base Classes for Containers
[3] Iterables vs. Iterators vs. Generators https://nvie.com/posts/iterators-vs-generators/ | 完全理解 Python 迭代对象, 迭代器, 生成器 http://python.jobbole.com/87805/
[4] Glossary 术语表 https://docs.python.org/3.7/glossary.html
[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
来源: http://www.jianshu.com/p/fb9148cfb332