TOC

Python 可迭代对象

可迭代对象(Iterable)就是可以用 for 循环遍历的数据结构,包括字符串、元组、列表、字典、集合等内置类型,也可以通过一些方法来是实现自定义可迭代对象。

https://docs.python.org/3/glossary.html#term-iterable
https://docs.python.org/3/glossary.html#term-iterator

迭代协议与序列协议

  • 迭代器协议(Iterator Protocol):如果一个对象包含 __next__ 方法,那就是一个迭代器。

迭代器可以使用 next 函数连续获取数据,内部实现就是调用 __next__ 方法获取一个数据项,如果循环结束,就会抛出 StopIteration

上面讲的是 CPython 实现,实际上 Python 语法规范要求迭代器一定要有 __iter__ 方法。
一般实现中,都有加上 __iter__ 方法,直接 return self

  • 可迭代对象协议(Iterable Protocol):如果一个对象包含 __iter__ 方法(返回一个迭代器对象),那么就是一个可迭代对象,

可以用在 for 循环,zipmapfilter 等需要可迭代对象的场景中。

  • 序列对象协议(Sequence Protocol):如果一个对象包含 __getitem__ 方法(使用 0 开始的整数作为索引),和 __len__ 方法,
    就可以执行一些序列对象的操作,比如...(?)。
    字符串,元组,列表都是序列对象。set 无序,dict 是按 key 索引,所以都不是序列对象。

  • 迭代器协议(Iterator Protocol):如果一个对象包含 __iter__ 方法,和 __next__ 方法,那就是一个迭代器。
    迭代器可以使用 next 函数连续获取数据,内部实现就是调用 __next__ 方法获取一个数据项,如果循环结束,就会抛出 StopIteration
    CPython 没有按照语言规范要求迭代器一定要有 __iter__ 方法。但一般实现中,都是加上 __iter__ 方法,return self

  • https://docs.python.org/3/c-api/abstract.html
  • Iterator Protocol https://docs.python.org/3/c-api/iter.html
  • Sequence Protocol https://docs.python.org/3/c-api/sequence.html

iter

iter(iterable)
iter(callable, sentinel) # sentinel:任意值都行

iter(1)
TypeError: 'int' object is not iterable
iter(1, 1)
TypeError: iter(v, w): v must be callable

iter 用于生成一个迭代器。

  • for 循环遍历的时候,会通过 iter 方法创建一个迭代器。
  • 可以创建迭代器的对象,必须支持 iterable protocol (包含 __iter__() 方法),
    或者支持 sequence protocol (包含 __getitem__() 方法,使用 0 开始的整数作为索引)

原理

迭代器(Iterator)

迭代器是可迭代对象的一种。它是一个具有 __iter__()__next__() 方法的对象,可以逐个返回可迭代对象的元素。
字符串、元组、列表、字典、集合这些内置类型就都不是迭代器。

PEP 234 – Iterators
https://peps.python.org/pep-0234/

自定义可迭代对象

class MyIterable:
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        self.index = 0
        return self

    def __next__(self):
        if self.index < len(self.data):
            result = self.data[self.index]
            self.index += 1
            return result
        else:
            raise StopIteration

a = MyIterable(['apple', 'banana', 'cherry'])
for item in a:
    print(item)