可迭代的对象、迭代器、生成器,几个概念密切关联,现将相关知识点整理如下。
1、可迭代对象(Iterable)
- 所有容器类型都是可迭代的,例如
- list, collections.deque, …
- dict, collections.defaultdict, collections.OrderedDict, collections.Counter, …
- tuple, collections.namedtuple, …
- set, …
- 对象实现了__iter__魔法方法,即为
可迭代对象
,内部函数iter,触发__iter__,其返回结果为迭代器对象
- 可迭代对象都可用
for
循环遍历,可以使用in
,not in
等运算符判断 - 对象如果未实现__iter__,而是实现了__getitem__,也是可迭代的,此乃python前向兼容的效果
- 如下
for
循环与while
循环等价
nums = [1, 2, 3]
# for 循环
for i in nums:
print(i)
# while 循环
nums = iter(nums)
while True:
try:
print(next(nums))
except StopIteration:
break
2、迭代器(Iterator)
- 同时实现了__iter__和__next__魔法函数的对象即为迭代器。__iter__返回self,__next__每调用一次返回一个元素
- 内部函数iter,next,分别触发魔法函数__iter__,__ next__
- __next__遍历结束后,应返回StopIteration异常
- 迭代器对象都是可迭代的
- 迭代器是一种设计模式(参阅fluent python)
3、生成器(Generator)
- 基本思想:生成器函数可以对执行过程进行控制和暂停,临时暂停并记录其执行到的行位置和局部变量值,将计算结果值逐个返回。这样无需一次计算出全部结果,而是逐个计算返回结果值,可以将对运行空间的需求降至最低,通过滚动或循环的方式生成值。进而便可以实现大体量数据的滚动加载和处理,而无需一次全部加载并计算完毕。(有待进一步深入到位总结)
- 所有生成器对象都是迭代器对象,可使用内置函数next调用。
- 生成器函数返回生成器对象,通过
yield
关键字输出值,python解释器在编译字节码时,即从生成器函数生成了生成器对象。 - 生成器对象有两种常用构造方式:
(1)生成器函数(带yield的函数)
(2)生成器表达式,格式为(expretion for statements)
- 举例一:斐波那契数列生成器实现
# 设fib(1)->0, fib(2)->1, fib(3)=fib(1)+fib(2), ...
def fib(n):
cur, nxt = 0, 1
for _ in range(n+1):
yield cur
cur, nxt = nxt, cur + nxt
for i in fib(5):
print(i)
- 举例二:大体量文本文件加载处理
# 文本文件500G,且仅有一行,常规逐行加载会超出内存
# 思路:采用f.read()按偏移量读入,然后流式处理
# 结合生成器方式,一边使用read读入,一边处理(按指定分割符拆分行),一边输出
# [ref] 视频课程:python3高级编程和异步IO并发编程,@bobby,p59
def myreadlines(f, divider):
buff = ''
while True:
chunk = f.read(4096)
buff += chunk
if not chunk: # 文件已加载完,抵达末尾
yield buff
break
while divider in buff:
pos = buff.index(divider) # 返回元素下标位置
yield buff[:pos]
buff = buff[pos+len(divider):]
with open('input.txt') as f:
for line in myreadlines(f, '|=|'):
print(line)
4、关系图
容器(container)、迭代(iteration)、可迭代对象(iterable)、迭代器(iterator)、生成器(generator)之间关系如下。
(图片来源: https://www.cnblogs.com/lvcm/p/9372622.html)