Python3 迭代器与生成器

可迭代对象与迭代器的区别、iter/next 协议、yield 生成器与生成器表达式。

Intermediate
Key Points可迭代对象有 __iter__,迭代器同时有 __iter__ 和 __next__;生成器函数用 yield 自动实现这两个方法。

迭代器

A for loop runs on the iterator protocol: iter(obj) yields an iterator, then next() is called until StopIteration. Anything implementing both methods can be looped over.

Python
xs = [1, 2]
it = iter(xs)

print(type(it).__name__)
print(next(it), next(it))
try:
    next(it)
except StopIteration:
    print("StopIteration")
Output
list_iterator
1 2
StopIteration

iter 与 next

next(it, default) supplies a fallback instead of raising. Iterators are one-shot: once exhausted they stay empty and do not rewind.

Python
it = iter([1, 2, 3])
print(next(it), next(it), next(it))
print(next(it, 'done'))

xs = [1, 2, 3]
print(list(xs), list(xs))

it2 = iter(xs)
print(list(it2), list(it2))
Output
1 2 3
done
[1, 2, 3] [1, 2, 3]
[1, 2, 3] []

创建迭代器

A custom class is a valid iterator once it implements __iter__ returning self and __next__ returning the next value or raising StopIteration.

Python
class Countdown:
    def __init__(self, start):
        self.n = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.n <= 0:
            raise StopIteration
        self.n -= 1
        return self.n + 1

print(list(Countdown(3)))
print([x for x in Countdown(5)])
Output
[3, 2, 1]
[5, 4, 3, 2, 1]

生成器

A function containing yield becomes a generator function: calling it runs no body, only returns a generator. Each next() runs to the next yield and pauses, preserving local state.

Python
def gen():
    print("start")
    yield 1
    print("resume")
    yield 2
    print("end")

g = gen()
print(type(g).__name__)
print(next(g))
print(next(g))
try:
    next(g)
except StopIteration:
    print("StopIteration")
Output
generator
start
1
resume
2
end
StopIteration

生成器表达式

Swap the brackets of a list comprehension for parentheses and you get a generator expression, lazily evaluated. For large files or datasets it avoids holding every result in memory at once.

Python
import sys

lst = [x * 2 for x in range(1000)]
gen = (x * 2 for x in range(1000))

print(len(lst), type(gen).__name__)
print(sys.getsizeof(lst) > sys.getsizeof(gen))
print(sum(gen))
print(sum(gen))
Output
1000 generator
True
999000
0

Friends & Partners