迭代器 vs 可迭代对象

一、一句话区分

  • 可迭代对象 Iterable:能被 for 循环“逐个拿出来”的东西(实现了 __iter__)。你可以反复向它要一个“发牌员”。

  • 迭代器 Iterator:真正“一个一个吐出来”的状态机(同时实现 __iter__ 返回自身 + __next__ 取下一个)。

生活化比喻:Iterable 像“一叠牌”,Iterable 自己不会发牌;Iterator 像“发牌员”,他手上记着发到哪一张了,你每次喊 next() 他就发下一张,发完就摊手说没了(StopIteration)。

二、Duck Typing 判断标准

角色必须实现的方法含义
可迭代对象 Iterable__iter__()(返回迭代器)“我能给你一个发牌员”
迭代器 Iterator__iter__()(返回 self)+ __next__()“我就是发牌员,每次发一张”

迭代器一定是可迭代对象(因为也有 __iter__),但可迭代对象不一定是迭代器(list 不是迭代器)。

三、关系与执行流程


graph LR

    A["for x in obj"] --> B["it = iter(obj)"]

    B --> C{obj 有 __iter__?}

    C -->|是| D["拿到 Iterator"]

    C -->|否 旧式 __getitem__| D

    D --> E["next(it) 每次取一个"]

    E -->|还有元素| D

    E -->|没了| F(["抛出 StopIteration\nfor 循环捕获后退出"])

四、可运行代码示例

 
from collections.abc import Iterable, Iterator
 
 
 
class CountDown:
 
    def __init__(self, n):
 
        self.n = n
 
    def __iter__(self):            # 可迭代对象:返回迭代器(这里返回自身)
 
        return self
 
    def __next__(self):            # 迭代器:返回下一项
 
        if self.n <= 0:
 
            raise StopIteration
 
        self.n -= 1
 
        return self.n
 
 
 
cd = CountDown(3)
 
print(isinstance(cd, Iterable))   # True
 
print(isinstance(cd, Iterator))   # True(因为 __iter__ 返回 self)
 
 
 
for x in cd:
 
    print(x)                      # 2 1 0
 
 
 
# list 是可迭代对象,但不是迭代器
 
lst = [1, 2, 3]
 
print(isinstance(lst, Iterable))  # True
 
print(isinstance(lst, Iterator))  # False
 
it = iter(lst)                    # 用内置 iter() 拿到迭代器
 
print(isinstance(it, Iterator))   # True
 
print(next(it), next(it))         # 1 2
 

五、核心考点

  1. 迭代器是“一次性”的:数据被“消费”后耗尽,再 next() 直接 StopIteration。想重新遍历需重新 iter(obj)

  2. 生成器(generator)一定是迭代器,但迭代器不一定是生成器——生成器只是写起来更省事的一种迭代器。

  3. for 循环底层:先 it = iter(obj),再不断 next(it),捕获 StopIteration 后悄悄退出。

  4. 为什么 list 不是迭代器:列表要保持“可重复遍历”,而迭代器会记住进度并消费数据(像网络流、大文件只能读一次,就必须用迭代器/生成器)。

六、对比速查表

可迭代对象 Iterable迭代器 Iterator
必须方法__iter____iter__ + __next__
能被 for 遍历
是否记住进度
能否重复遍历❌(一次性)
典型例子list / dict / str / setiter(list)、生成器

速记卡(面试闪卡)

Q1:一句话讲清「迭代器 vs 可迭代对象」到底是什么?

A:可迭代对象(Iterable)有 iter,迭代器(Iterator)额外有 next,是能逐个吐数据的状态机。

Q2:一、一句话区分 —— 怎么理解?

A:Iterable 像”一叠牌”,自己不会发牌,只能给你一个发牌员;Iterator 像”发牌员”(Dealer),手上记着发到哪张,你每次喊 next() 它就发下一张,发完抛 StopIteration。Iterable 实现了 iter,Iterator 额外实现 next(迭代器协议,Iterator Protocol)。

Q3:二、Duck Typing 判断标准 —— 怎么理解?

A:判断只看”会不会这两招”:Iterable 必须有 iter()(返回迭代器),“我能给你一个发牌员”;Iterator 必须有 iter()(返回 self)+ next(),“我就是发牌员”。所以迭代器一定是可迭代对象(鸭子类型,Duck Typing),但 list 有 iternext,得用 iter(list) 才拿到迭代器。

Q4:三、关系与执行流程 —— 怎么理解?

A:for x in obj 底层先 it = iter(obj) 拿到迭代器,再不断 next(it),捕获 StopIteration 后悄悄退出——像自动按铃的发牌机。任何能被 for 遍历的东西(生成器、range、文件)最终都靠 next 一个一个给值,理解这点就通了。

Q5:四、可运行代码示例 —— 怎么理解?

A:CountDown 类 iter 返回 self、next 返回下一项并在到 0 时抛 StopIteration,所以它既是 Iterable 也是 Iterator。list 是 Iterable 但不是 Iterator——list 要保持可重复遍历,故意不做成”一次性”状态机,需要时 iter(list) 才生成新迭代器(惰性求值,Lazy Evaluation)。

Q6:核心速记主线有哪些?

  • 可迭代对象 Iterable 有 iter,迭代器 Iterator 有 iter + next

  • 迭代器一定是 Iterable,但 list 不是迭代器

  • for 底层 = iter() + next() + 捕获 StopIteration

  • 迭代器一次性消费、list 可重复;生成器必是迭代器

口诀

A:Iterable 一叠牌,Iterator 发牌员;

前者 iter 给,后者 next 添;

迭代器一次性,StopIteration 断;

list 非迭代器,iter() 才见面。

相关链接