python中的迭代器与生成器

迭代器:

两个基本的方法:iter()next()

  • __iter__() 方法返回一个特殊的迭代器对象, 这
  • 个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
  • __next__() 方法会返回下一个迭代器对象。

核心区分

class MyNumbers: def __iter__(self): self.a = 1 return self # 返回自己,作为迭代器 def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() it = iter(myclass) # 执行 __iter__,self.a=1,返回对象self print(it) # 打印对象:<__main__.MyNumbers object at 0x...> print(next(it)) # 调用 __next__ → 1 print(next(it)) # 调用 __next__ → 2
  • iter(x)→ 调用x.__iter__()得到迭代器对象

    print(iter(myclass)) # 输出类似:<__main__.MyNumbers object at 0x0000021xxxx>

    打印出来的是对象描述、内存地址,不会执行next,不会产生 1、2、3 这种数据

执行iter(myclass)的时候:

  1. 会跑__iter__里面代码:self.a =1✅(状态初始化发生在这里!)
  2. return self返回实例对象
  3. 但是不会调用__next__,不会计算、不会返回数字
  4. 这一步打印不会输出业务数据(数字、列表这些),它返回的是迭代器对象本身,打印对象看到的是对象内存信息,不是迭代产出的值。
  • next(迭代器对象)→ 调用__next__()才拿到实际的元素值

    it = iter(myclass) print(next(it)) # 输出 1

📌一句话记忆:iter()负责造迭代器工具;next()负责驱动工具产出数据。

总结表

代码执行的方法返回什么print 之后看到什么
iter(x)x.__iter__()迭代器对象对象内存信息,没有业务数据
next(it)it.__next__()迭代出来的元素真实数据,比如1,2,3

易错点提醒:

__iter__只是做初始化、返回迭代器;真正产生每一个值,是交给next/ next()

就算__iter__内部初始化了self.a=1,这个 1 只是变量状态,不会自动跑出来,必须等next()调用__next__才会取出来返回。

生成器函数(带 yield):

只要 Python 看到函数定义体内存在 yield,它就把这个函数标记为生成器函数。

def gen(): yield 10 g = gen() # 等价于 iter(...) 的效果,拿到生成器迭代器对象。生成器自动实现iter和next,简化代码 print(g) # <generator object gen at 0x...>,打印对象,拿不到10 print(next(g)) # 10,next才会拿到产出的值

运行实例:

def gen(): print("开始执行函数内部") yield 100 g = gen() # 第0步,仅仅构造生成器,返回一个生成器对象,这个对象处于休眠状态,需要next唤醒,并没有执行函数 print("这里是g = gen()之后")#打印结果 print(next(g))#激活对象之后,开始执行函数,根据函数定义先打印"开始执行函数内部",再通过yield输出100

调用生成器函数时:

  • 不执行函数里面任何一行代码
  • 直接返回一个「生成器对象」,保存函数的入口位置、局部变量的上下文
  • 这个对象处于休眠状态,等着 next() 来唤醒
  • yield 不是 return。
  • yield 是暂停指令,它生效的前提是代码执行流走到这一行。 没被 next 唤醒,代码流根本走不到 yield a 那一行,自然不可能输出 a。
#以下是执行结果 这里是g = gen()之后 开始执行函数内部 100

区分两件事(极易混淆):

  1. 函数定义里面写了 yield:只是告诉 Python,这是生成器。此时什么都不发生。
  2. 程序执行流运行到 yield 这行语句:才会暂停 + 向外产出值。

写在代码里 ≠ 程序已经跑到这行执行了。

一句话记住规则

  • yield a≠ 立刻把 a 算出来返回
  • yield a只是定义了一个「将来被 next () 调用时,要产出什么值」。
  • 函数只有遇到 next () /for 循环才会真正跑内部代码。