Skip to content

Python 迭代器与生成器

迭代器和生成器是 Python 中处理可迭代对象的重要概念。本章节将详细介绍 Python 中的迭代器和生成器。

迭代器

迭代器是一个实现了 __iter__()__next__() 方法的对象。它可以逐个返回元素,直到没有元素可返回时抛出 StopIteration 异常。

迭代器协议

迭代器协议是指对象必须实现以下两个方法:

  1. __iter__():返回迭代器对象本身。
  2. __next__():返回下一个元素,如果没有更多元素,则抛出 StopIteration 异常。

创建迭代器

可以通过以下两种方式创建迭代器:

  1. 使用内置的 iter() 函数将可迭代对象转换为迭代器。
  2. 自定义一个实现了迭代器协议的类。

使用 iter() 函数

示例:

python
# 使用 iter() 函数创建迭代器

# 列表
my_list = [1, 2, 3, 4, 5]
iter_list = iter(my_list)
print(next(iter_list))  # 输出:1
print(next(iter_list))  # 输出:2
print(next(iter_list))  # 输出:3
print(next(iter_list))  # 输出:4
print(next(iter_list))  # 输出:5
# print(next(iter_list))  # 抛出 StopIteration 异常

# 字符串
my_string = "hello"
iter_string = iter(my_string)
print(next(iter_string))  # 输出:h
print(next(iter_string))  # 输出:e
print(next(iter_string))  # 输出:l
print(next(iter_string))  # 输出:l
print(next(iter_string))  # 输出:o
# print(next(iter_string))  # 抛出 StopIteration 异常

# 元组
my_tuple = (1, 2, 3)
iter_tuple = iter(my_tuple)
print(next(iter_tuple))  # 输出:1
print(next(iter_tuple))  # 输出:2
print(next(iter_tuple))  # 输出:3
# print(next(iter_tuple))  # 抛出 StopIteration 异常

自定义迭代器

示例:

python
# 自定义迭代器

class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.end:
            value = self.current
            self.current += 1
            return value
        else:
            raise StopIteration

# 使用自定义迭代器
my_iter = MyIterator(1, 5)
print(next(my_iter))  # 输出:1
print(next(my_iter))  # 输出:2
print(next(my_iter))  # 输出:3
print(next(my_iter))  # 输出:4
# print(next(my_iter))  # 抛出 StopIteration 异常

# 在 for 循环中使用迭代器
print("\n在 for 循环中使用迭代器:")
my_iter = MyIterator(1, 5)
for num in my_iter:
    print(num, end=" ")  # 输出:1 2 3 4
print()

# 再次使用迭代器(需要重新创建)
print("\n再次使用迭代器:")
my_iter = MyIterator(1, 5)
for num in my_iter:
    print(num, end=" ")  # 输出:1 2 3 4
print()

迭代器的特点

  1. 一次性:迭代器只能遍历一次,遍历完后需要重新创建。
  2. 惰性计算:迭代器按需生成元素,节省内存。
  3. 不可回退:迭代器只能向前移动,不能回退。
  4. 可迭代:迭代器本身是可迭代的,因为它实现了 __iter__() 方法。

示例:

python
# 迭代器的特点

# 一次性
print("迭代器的一次性:")
my_list = [1, 2, 3]
iter_list = iter(my_list)
print(list(iter_list))  # 输出:[1, 2, 3]
print(list(iter_list))  # 输出:[](已遍历完)

# 惰性计算
print("\n迭代器的惰性计算:")
# 生成器表达式是一种惰性计算
my_generator = (i**2 for i in range(1000000))
print("生成器已创建,但尚未计算元素")
print(next(my_generator))  # 输出:0(按需计算)
print(next(my_generator))  # 输出:1(按需计算)

# 不可回退
print("\n迭代器的不可回退:")
my_list = [1, 2, 3]
iter_list = iter(my_list)
print(next(iter_list))  # 输出:1
print(next(iter_list))  # 输出:2
# 无法回到上一个元素
print(next(iter_list))  # 输出:3

# 可迭代
print("\n迭代器的可迭代性:")
my_list = [1, 2, 3]
iter_list = iter(my_list)
print(iter(iter_list) is iter_list)  # 输出:True(迭代器的 __iter__() 方法返回自身)

生成器

生成器是一种特殊的迭代器,它使用 yield 语句来返回元素,而不是 return 语句。生成器更加简洁、高效,是创建迭代器的首选方式。

创建生成器

可以通过以下两种方式创建生成器:

  1. 使用生成器表达式。
  2. 定义一个包含 yield 语句的函数。

生成器表达式

生成器表达式与列表推导式类似,但使用圆括号 () 而不是方括号 []

示例:

python
# 生成器表达式

# 基本用法
print("基本用法:")
gen = (i**2 for i in range(5))
print(gen)  # 输出:<generator object <genexpr> at 0x...>

# 遍历生成器
for num in gen:
    print(num, end=" ")  # 输出:0 1 4 9 16
print()

# 带条件的生成器表达式
print("\n带条件的生成器表达式:")
gen = (i for i in range(10) if i % 2 == 0)
for num in gen:
    print(num, end=" ")  # 输出:0 2 4 6 8
print()

# 复杂表达式的生成器表达式
print("\n复杂表达式的生成器表达式:")
words = ["hello", "world", "python"]
gen = (word.upper() for word in words)
for word in gen:
    print(word, end=" ")  # 输出:HELLO WORLD PYTHON
print()

生成器函数

生成器函数是一个包含 yield 语句的函数,调用时返回一个生成器对象。

示例:

python
# 生成器函数

def my_generator():
    yield 1
    yield 2
    yield 3
    yield 4
    yield 5

# 使用生成器函数
gen = my_generator()
print(gen)  # 输出:<generator object my_generator at 0x...>

# 遍历生成器
print("遍历生成器:")
for num in gen:
    print(num, end=" ")  # 输出:1 2 3 4 5
print()

# 再次使用生成器(需要重新调用函数)
print("\n再次使用生成器:")
gen = my_generator()
for num in gen:
    print(num, end=" ")  # 输出:1 2 3 4 5
print()

yield 语句

yield 语句的作用是:

  1. 暂停函数执行,返回当前值。
  2. 保存函数的状态,下次调用时从暂停的地方继续执行。

示例:

python
# yield 语句的工作原理

def count_up_to(n):
    print("开始计数")
    i = 0
    while i < n:
        print(f"准备返回 {i}")
        yield i
        i += 1
        print(f"继续执行,i = {i}")
    print("计数结束")

# 使用生成器
gen = count_up_to(3)
print("生成器已创建")

print("\n第一次调用 next():")
print(next(gen))  # 输出:开始计数 准备返回 0 0

print("\n第二次调用 next():")
print(next(gen))  # 输出:继续执行,i = 1 准备返回 1 1

print("\n第三次调用 next():")
print(next(gen))  # 输出:继续执行,i = 2 准备返回 2 2

print("\n第四次调用 next():")
try:
    print(next(gen))  # 输出:继续执行,i = 3 计数结束
except StopIteration:
    print("StopIteration 异常")

生成器的特点

  1. 惰性计算:生成器按需生成元素,节省内存。
  2. 一次性:生成器只能遍历一次,遍历完后需要重新创建。
  3. 状态保存:生成器保存函数的状态,下次调用时从暂停的地方继续执行。
  4. 简洁高效:生成器代码更加简洁、高效,是创建迭代器的首选方式。

示例:

python
# 生成器的特点

# 惰性计算
print("生成器的惰性计算:")
def infinite_sequence():
    i = 0
    while True:
        yield i
        i += 1

# 创建生成器
gen = infinite_sequence()
print("生成器已创建,不会立即执行")

# 按需生成元素
print(next(gen))  # 输出:0
print(next(gen))  # 输出:1
print(next(gen))  # 输出:2

# 状态保存
print("\n生成器的状态保存:")
def countdown(n):
    while n > 0:
        yield n
        n -= 1

gen = countdown(3)
print(next(gen))  # 输出:3
print("暂停执行")
print(next(gen))  # 输出:2
print("暂停执行")
print(next(gen))  # 输出:1

# 简洁高效
print("\n生成器的简洁高效:")
# 生成器表达式
print("生成器表达式:")
gen = (i**2 for i in range(10))
print(list(gen))  # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 生成器函数
print("\n生成器函数:")
def squares(n):
    for i in range(n):
        yield i**2

gen = squares(10)
print(list(gen))  # 输出:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

生成器的高级特性

send() 方法

生成器的 send() 方法用于向生成器发送一个值,并继续执行生成器,返回下一个 yield 语句的结果。

示例:

python
# send() 方法

def echo_generator():
    print("生成器已启动")
    while True:
        received = yield
        print(f"收到:{received}")

# 创建生成器
gen = echo_generator()

# 启动生成器(第一次调用 next() 或 send(None))
next(gen)  # 输出:生成器已启动

# 发送值
gen.send("Hello")  # 输出:收到:Hello
gen.send("World")  # 输出:收到:World

# 关闭生成器
gen.close()

# 再次发送值会抛出异常
# gen.send("Python")  # StopIteration

throw() 方法

生成器的 throw() 方法用于向生成器抛出一个异常,并继续执行生成器,返回下一个 yield 语句的结果。

示例:

python
# throw() 方法

def error_generator():
    try:
        yield 1
        yield 2
        yield 3
    except ValueError as e:
        print(f"捕获到 ValueError:{e}")
        yield 4
        yield 5
    finally:
        print("生成器结束")

# 创建生成器
gen = error_generator()

# 正常执行
print(next(gen))  # 输出:1
print(next(gen))  # 输出:2

# 抛出异常
print(gen.throw(ValueError, "测试错误"))  # 输出:捕获到 ValueError:测试错误 4

# 继续执行
print(next(gen))  # 输出:5

# 再次调用会抛出 StopIteration
# print(next(gen))  # 输出:生成器结束 StopIteration

close() 方法

生成器的 close() 方法用于关闭生成器,释放资源。关闭后再次调用 next()send() 会抛出 StopIteration 异常。

示例:

python
# close() 方法

def my_generator():
    try:
        yield 1
        yield 2
        yield 3
    finally:
        print("生成器已关闭")

# 创建生成器
gen = my_generator()

# 正常执行
print(next(gen))  # 输出:1
print(next(gen))  # 输出:2

# 关闭生成器
gen.close()  # 输出:生成器已关闭

# 再次调用会抛出 StopIteration
# print(next(gen))  # StopIteration

迭代器与生成器的应用场景

迭代器和生成器在以下场景中特别有用:

  1. 处理大量数据:当数据量很大时,使用迭代器或生成器可以节省内存。
  2. 惰性计算:当只需要按需处理数据时,使用迭代器或生成器可以提高效率。
  3. 无限序列:当需要处理无限序列时,只能使用生成器。
  4. 管道处理:当需要对数据进行多步处理时,使用生成器可以构建数据处理管道。

处理大量数据

示例:

python
# 处理大量数据

# 列表推导式(占用大量内存)
print("使用列表推导式:")
import sys
large_list = [i**2 for i in range(1000000)]
print(f"列表大小:{sys.getsizeof(large_list)} 字节")
del large_list  # 释放内存

# 生成器表达式(占用很少内存)
print("\n使用生成器表达式:")
large_generator = (i**2 for i in range(1000000))
print(f"生成器大小:{sys.getsizeof(large_generator)} 字节")

# 按需处理
print("\n按需处理数据:")
for i, num in enumerate(large_generator):
    if i < 5:
        print(num, end=" ")  # 输出:0 1 4 9 16
    else:
        break
print()

惰性计算

示例:

python
# 惰性计算

# 生成器函数
print("使用生成器函数进行惰性计算:")
def process_data(data):
    for item in data:
        # 模拟复杂的处理
        result = item * 2
        yield result

# 创建数据
my_data = [1, 2, 3, 4, 5]

# 创建生成器
processor = process_data(my_data)
print("生成器已创建,尚未处理数据")

# 按需处理
print("\n按需处理数据:")
print(next(processor))  # 输出:2(处理第一个元素)
print(next(processor))  # 输出:4(处理第二个元素)
print(next(processor))  # 输出:6(处理第三个元素)

无限序列

示例:

python
# 无限序列

# 生成器函数
print("使用生成器函数创建无限序列:")
def infinite_fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 创建生成器
fib = infinite_fibonacci()

# 按需获取元素
print("\n获取前 10 个斐波那契数:")
for i in range(10):
    print(next(fib), end=" ")  # 输出:0 1 1 2 3 5 8 13 21 34
print()

管道处理

示例:

python
# 管道处理

# 生成器函数
print("使用生成器函数构建数据处理管道:")

def read_data():
    """读取数据"""
    data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    for item in data:
        yield item

def filter_data(data):
    """过滤数据"""
    for item in data:
        if item % 2 == 0:
            yield item

def process_data(data):
    """处理数据"""
    for item in data:
        yield item * 2

def write_data(data):
    """写入数据"""
    result = []
    for item in data:
        result.append(item)
    return result

# 构建管道
pipeline = write_data(process_data(filter_data(read_data())))

# 执行管道
print("处理结果:")
print(pipeline)  # 输出:[4, 8, 12, 16, 20]

总结

本章节介绍了 Python 中的迭代器和生成器:

  1. 迭代器:实现了 __iter__()__next__() 方法的对象,用于逐个返回元素。
  2. 生成器:一种特殊的迭代器,使用 yield 语句来返回元素,更加简洁、高效。
  3. 生成器表达式:与列表推导式类似,但使用圆括号,返回生成器对象。
  4. 生成器函数:包含 yield 语句的函数,调用时返回生成器对象。
  5. 生成器的高级特性:包括 send()throw()close() 方法。
  6. 应用场景:处理大量数据、惰性计算、无限序列、管道处理等。

掌握迭代器和生成器的使用对于编写高效的 Python 代码非常重要。