Python——迭代器和生成器

引子:迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。

迭代器

一、迭代器是什么

迭代器是一个可以记住遍历的位置的对象。

二、迭代器的特点

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器必须有的两个方法:iter() 和 next()。

三、哪些数据类型是可迭代的(iterable)?

字符串、列表、元组、字典、集合都是可迭代的。

四、代码演示

1.迭代器的用法

list = [1, 2, 3, 4]     # 创建一个列表
it = iter(list)     # 创建一个迭代器对象
print(next(it))     # 输出迭代器的下一个元素
print(next(it))     # 持续迭代
...

上面代码里,我们先创建了一个列表,然后把列表作为一个参数传给iter方法,生成一个迭代器对象it。再讲迭代器对象作为参数传给next方法,从而实现持续向下迭代。且每一次调用next,都会在列表里向后取一个值。如果超出列表的长度,则会报错 StopIteration。

2.模拟实现一个简单的迭代器

class MyIterator:
    def __iter__(self):  # 模拟实现 iter 方法
        self.a = 1      # 实例属性,属于这个迭代器对象,对象不销毁,这个值就一直保存
        return self     # iter方法要求返回一个迭代器对象,这里是把自己这个实例对象当做迭代器返回
    def __next__(self):  # 模拟实现 next 方法
        self.a += 1
        if self.a > 20:
            raise StopIteration     # 主动抛出异常,防止无限循环——StopIteration 异常用于标识迭代的完成
        return self.a



myclass = MyIterator()    # 创建一个实例对象
myiter = iter(myclass)    # 创建一个迭代器对象
while True:
    print(next(myiter))     # 循环便利迭代器的下一个

借助讲解这个实现过程,顺便复习一下面向对象的知识。

形如“__iter__”这种格式的方法,在Python中为魔法方法,常见于类中初始化方法“__init__”。

self.a 是实例属性(对象变量)

  • self 代表当前 MyIterator 的这个迭代器对象本身
  • self.a 就是绑定在这个对象身上的变量,用来记录迭代的当前状态(计数器)

普通局部变量是写在函数里面、函数调用完就消失; self.a 是挂在对象上,多次调用 __next__ 的时候,值可以保留、持续累加,这是迭代器最关键的一点。

如果直接在方法里创建局部变量 a ,每次 __next__ 调用结束就销毁,记不住上一次数字,迭代器就没法工作。

__iter__ 要求返回一个迭代器对象; return self 就是:把自己这个实例对象,当做迭代器返回出去。 这里的 self = 当前 MyIterator() 创建出来的那个对象。

记住一条 Python 迭代器规则: 一个对象只要同时有 __iter__ + __next__,它自己本身就是迭代器。

1. self 到底是什么?

当你写:

it = MyIterator()

it 就是这个对象,在类里面,self 就是这个 it 的别名。

  • self 不是一个普通变量,它是自动传进来的第一个参数,代表当前实例
  • self 里面存着:
    1. 绑定在它身上的实例属性:比如 self.a
    2. 绑定在它身上的方法:self.__next__()、self.__iter__()

你可以理解成: self 是一个小盒子,盒子里面装着我们这个迭代器需要的状态(计数器 a),还有它能执行的动作(__next__)。

self(盒子/对象)
├─ 属性:self.a
└─ 方法:__iter__、__next__

2. 为什么 iter 可以 return self?

迭代协议两条规则:

  1. iter(对象) → 调用对象的 __iter__(),必须返回一个迭代器
  2. 迭代器必须有 __next__() 方法,next() 函数会去调用它

MyIterator 实例刚好满足:它自己就带 __next__,它自己就是迭代器。 所以 __iter__ 直接把自己交出去:return self。

很多初学者会疑惑:为什么不新建一个别的对象返回? 当然也可以返回别的迭代器对象! 比如容器类(list、字典),__iter__ 返回一个全新的迭代器,而不是自己。

✅ 两种写法都合法:

  • 方式 A(你现在这种:自迭代器):__iter__ return self,自己既是可迭代对象,又是迭代器
  • 方式 B(容器常用):__iter__ 返回一个独立的迭代器实例,容器本身不是迭代器

3.对比感受差别(自迭代器VS独立迭代器)

列表就是方式 B:

lst = [1,2,3]
i1 = iter(lst)
i2 = iter(lst)
print(i1 is lst) # False,返回新迭代器,列表本身不是迭代器

而我们的代码是方式 A:

it = MyIterator()
i1 = iter(it)
print(i1 is it) # True,自己就是迭代器

4. 重点坑点:自迭代器(return self)的副作用

因为可迭代对象和迭代器是同一个,它只有一份状态 self.a: 一旦迭代一遍跑完,self.a 到 20 抛出异常;再次 for 循环遍历它,不会重新从头开始!

it = MyIterator()
for x in it:
    print(x)
# 再循环一次,直接空,不会重新从2开始
for x in it:
    print(x)

原因:self.a 的状态已经停在 20 了,__iter__ 只有在你第一次 iter 的时候才会重置 self.a=1。

这就是为什么真实开发里,容器一般不采用 return self,而是返回独立迭代器。

5. 总结极简版

  1. self:当前实例对象,里面保存实例属性(self.a)和方法
  2. __iter__ 的任务:交出一个迭代器
  3. return self 的含义:我自己就是迭代器,直接把我交给 for 循环 /next 函数去使用
  4. 前提:这个对象必须实现 __next__,否则交出去也没法 next ()

生成器

待补充……


参考文章:

python之路——迭代器和生成器 - Eva_J - 博客园

posted @ 2026-11-02 16:42  Treant、  阅读(3)  评论(0)    收藏  举报