深入理解可迭代对象、迭代器、生成器的区别

魔术方法可参看: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 异常
  • 迭代器是实现了迭代器协议的容器对象
  • 迭代器的实现(迭代器协议):
    1. 可迭代,因此内部需实现__iter__方法
    2. 可用 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

总结

  1. 可迭代对象(Iterable):是一种可以迭代的对象,通常是指可以使用 for 循环进行遍历的对象,例如列表、元组、集合、字典等。它们可以通过内置函数 iter() 转换为迭代器
  2. 迭代器(Iterator):迭代器是一个实现了迭代器协议(Iterator Protocol)的对象,迭代器协议需要实现两个方法: __iter__()__next__() 方法。__iter__() 方法返回迭代器对象本身,__next__() 方法返回迭代器中的下一个元素。当迭代器中没有元素时,__next__() 方法会引发 StopIteration 异常
  3. 生成器(Generator):是一种特殊的迭代器,它使用 yield 语句来生成值序列。生成器函数使用 yield 语句来暂停其执行,并在调用方请求下一个值时继续执行。生成器可以使用 for 循环进行遍历,也可以使用 next() 函数手动获取下一个值
    总的来说,可迭代对象是一种可以遍历的对象,迭代器是一类实现了迭代器协议的对象,而生成器是一种特殊的迭代器,使用 yield 语句生成值序列

参考


  1. Python 中的可迭代对象、迭代器和生成器
  2. 迭代器、可迭代对象、生成器详解
  3. 简述生成器 | 迭代器 | 可迭代对象 | 以及应用场景