Python中迭代器内的变量是如何保存的?

有下面一段代码,分别打印 1 1 2 3 5 和 0 0 0 0 0,请问后面一个迭代器为什么不会打印 0 1 2 3 4 ?

class Fib(object):
    def __init__(self):
        self.prev = 0
        self.curr = 1
    def next(self):
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value
    def __iter__(self):
        return self

class T(object): def iter(self): return self def next(self): for i in range(5): return i

f = Fib() t = T()

print next(f) print next(f) print next(f) print next(f) print next(f)

print next(t) print next(t) print next(t) print next(t) print next(t)


Python中迭代器内的变量是如何保存的?

11 回复

因为已经 return 了,后面 i=1,2,3,4 根本不会运行


在Python里,迭代器内部变量的保存方式其实挺直接的,主要看这个迭代器是怎么实现的。

最常见的就是用生成器函数(带 yield 的函数)。当函数执行到 yield 时,它会暂停,并把所有局部变量、指令指针这些状态都保存在一个生成器对象里。下次调用 next(),它就从上次暂停的地方接着跑,变量值当然也还在。

给你看个例子就明白了:

def my_counter(start):
    print("生成器初始化")
    count = start
    while True:
        print(f"yield前,count = {count}")
        yield count
        count += 1
        print(f"yield后,count = {count}")

# 创建生成器对象
counter = my_counter(5)

# 第一次next
print("第一次next:")
val1 = next(counter)  # 输出: 生成器初始化 \n yield前,count = 5
print(f"拿到值: {val1}\n")

# 第二次next
print("第二次next:")
val2 = next(counter)  # 输出: yield后,count = 6 \n yield前,count = 6
print(f"拿到值: {val2}\n")

# 第三次next
print("第三次next:")
val3 = next(counter)  # 输出: yield后,count = 7 \n yield前,count = 7
print(f"拿到值: {val3}")

运行这个,你会看到 count 这个变量在每次 yield 暂停时都被“冻住”了,下次恢复时值完全保留。它和闭包有点像,但机制不同:闭包是靠外层函数的栈帧,而生成器是把自己的整个栈帧(包括局部变量)保存下来。

如果是自己写迭代器类(实现 __iter____next__),那更简单:变量就是作为实例属性(self.xxx)存着的,每次 __next__ 调用都能访问到。

所以核心就一句话:迭代器的状态(包括变量)保存在它的执行帧或对象属性里,靠这个实现暂停和恢复。

yield 才是给迭代器用的

查一查 magic method

Next 调用的是 next 这个方法

但是第一个 Fib 的实例就运行了。

迭代器只要求有 next 和__iter__,yield 是给生成器函数用的。

__next__是 Python 3 的方法,Python 2 的叫 next。

#1 说的对,每次你用 next(t) 的時候,就調用一次 t.next()。你可以在[這裏]( http://pythontutor.com/visualize.html) 寫下你的代碼,可視化你的執行步驟。

for i in range(5):
return i

楼主你再看看?

Fib 的話,記錄了當前迭代的狀態,所以完全沒問題

迭代器只要求有 next 和__iter__,yield 是给生成器函数用的。

一般也是用 yield 实现 next,用 return 不是不行,多麻烦啊

回到顶部