深入理解可迭代对象、迭代器、生成器的区别
魔术方法可参看:python学习笔记:魔术方法
可迭代对象
- 可迭代对象:可以用 for 循环来迭代的对象
- 可迭代对象必须满足可迭代的协议
- 如果对象实现了能返回迭代器的
__iter__
方法(必须返回迭代器对象),则对象是可迭代的 - 如果没有实现
__iter__
方法,实现了__getitem__
方法且其参数是从零开始索引的,这种对象也是可迭代的
测试是否是可迭代对象
- for _ in o:可识别仅实现了
__getitem__
的可迭代对象 o - isinstance()、issubclass():不可识别仅实现了
__getitem__
的可迭代对象 - iter():可识别仅实现了
__getitem__
的可迭代对象
# 例1:
from collections.abc import Iterable,Iterator
# 测试list类和实例
# 显然list类对象是可迭代的,但不是迭代器
print(isinstance([], Iterable), isinstance([], Iterator))
print(issubclass(list, Iterable), issubclass(list, Iterator))
class A:
def __init__(self):
self.items = []
def add(self, value):
return self.items.append(value)
def __iter__(self):
# return 123 # TypeError: iter() returned non-iterator of type 'int'
return iter(self.items)
def __getitem__(self, item):
return self.items[item]
a = A()
a.add(1)
for i in a:
print(i)
print(isinstance(a, Iterable), isinstance(a, Iterator))
print(issubclass(A, Iterable), issubclass(A, Iterator))
print(iter(a)) # 若未实现__iter__方法和__getiterm__,则报TypeError: 'A' object is not iterable
迭代器
- 迭代器:可以被 next() 函数调用并不断返回下一个值的对象称为迭代器,直到最后抛出 StopIteration 异常
- 迭代器是实现了迭代器协议的容器对象
- 迭代器的实现(迭代器协议):
- 可迭代,因此内部需实现
__iter__
方法 - 可用 next() 函数惰性取值,因此内部需实现
__next__
方法
- 可迭代,因此内部需实现
- 迭代器是可迭代对象,可用 for 来循环遍历,内部捕获了异常,不会抛出 StopIteration
- list、set、dirt、str 等是可迭代对象,但不是迭代器,但可以通过 iter() 函数获得一个迭代器对象
from collections.abc import Iterator
class A:
def __init__(self):
self.items = []
self.index = 0
def add(self, value):
self.items.append(value)
return self
def __iter__(self):
for item in self.items:
yield item
self.index += 1
def __next__(self):
try:
item = self.items[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return item
a = A()
a.add(100).add(200)
# for i in a:
# print(i)
print(a.index)
print(next(a)) # 如果先遍历完,a.index就在末尾,再调用next()就会抛StopIteration异常
print(a.index)
print(next(a))
print(a.index)
# print(next(a)) # StopIteration
print(isinstance(a, Iterator))
# 判断迭代器是否是生成器
generator = type(a.__iter__())
print(generator)
print(isinstance(a, generator))
-----------------------------------------
0
100
1
200
2
True
<class 'generator'>
False
生成器
- 对于生成器和生成器表达式可参考章节推导式和生成器
- 生成器是可迭代对象,也是迭代器
- 生成器是是一种特殊的迭代器
- 生成器通过生成器表达式和生成器函数(关键字 yield/yield from)实现
from collections.abc import Iterable,Iterator
import types
print(types.GeneratorType)
g = (i for i in range(5, 10))
print(g)
print(next(g))
print(next(g))
print(isinstance(g, Iterable), isinstance(g, Iterator), isinstance(g, types.GeneratorType))
def gen():
yield from range(5, 10)
ge = gen()
print(next(ge))
print(next(ge))
print(isinstance(ge, Iterable), isinstance(ge, Iterator), isinstance(ge, types.GeneratorType))
-----------------------------------------------------------------------
<class 'generator'>
<generator object <genexpr> at 0x0000028C637730A0>
5
6
True True True
5
6
True True True
总结
- 可迭代对象(Iterable):是一种可以迭代的对象,通常是指可以使用 for 循环进行遍历的对象,例如列表、元组、集合、字典等。它们可以通过内置函数 iter() 转换为迭代器
- 迭代器(Iterator):迭代器是一个实现了迭代器协议(Iterator Protocol)的对象,迭代器协议需要实现两个方法:
__iter__()
和__next__()
方法。__iter__()
方法返回迭代器对象本身,__next__()
方法返回迭代器中的下一个元素。当迭代器中没有元素时,__next__()
方法会引发 StopIteration 异常 - 生成器(Generator):是一种特殊的迭代器,它使用 yield 语句来生成值序列。生成器函数使用 yield 语句来暂停其执行,并在调用方请求下一个值时继续执行。生成器可以使用 for 循环进行遍历,也可以使用 next() 函数手动获取下一个值
总的来说,可迭代对象是一种可以遍历的对象,迭代器是一类实现了迭代器协议的对象,而生成器是一种特殊的迭代器,使用 yield 语句生成值序列