跳到主要内容

Python 迭代器与生成器

在Python编程中,处理数据集合和序列是一项常见任务。当我们需要遍历大量数据或者创建复杂的数据流时,迭代器和生成器就成为了非常强大的工具。它们不仅可以提高代码的性能,还能让我们的代码更加优雅和可读。

什么是迭代与迭代器

迭代的概念

迭代是指重复执行特定操作的过程,通常用于处理序列中的每个元素。在Python中,我们经常使用for循环来迭代序列,如列表、元组、字典等。

python
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)

输出:

apple
banana
cherry

当你使用for循环遍历一个对象时,Python实际上在背后调用了迭代器机制。

迭代器的定义

**迭代器(Iterator)**是一个对象,它实现了迭代器协议,包含两个方法:

  1. __iter__(): 返回迭代器对象本身
  2. __next__(): 返回下一个值,如果没有更多的值可以返回,则引发StopIteration异常

可迭代对象(Iterable)是任何可以返回迭代器的对象,它实现了__iter__()方法。

使用内置函数操作迭代器

Python提供了一些内置函数来操作迭代器:

  • iter(): 从可迭代对象创建迭代器
  • next(): 获取迭代器的下一个值
python
# 创建一个迭代器
my_list = [1, 2, 3]
my_iterator = iter(my_list)

# 使用next()获取元素
print(next(my_iterator)) # 1
print(next(my_iterator)) # 2
print(next(my_iterator)) # 3

# 当没有更多元素时,会引发StopIteration异常
try:
print(next(my_iterator))
except StopIteration:
print("迭代器已经用尽")

输出:

1
2
3
迭代器已经用尽

创建自定义迭代器

你可以创建自己的迭代器类,只需实现__iter__()__next__()方法:

python
class CountDown:
def __init__(self, start):
self.start = start

def __iter__(self):
return self

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

# 使用自定义迭代器
countdown = CountDown(5)
for i in countdown:
print(i)

输出:

5
4
3
2
1

生成器:简化迭代器的创建

生成器(Generator)是创建迭代器的简单而强大的工具。它使用yield语句而不是return语句返回值,每次生成一个值后会"暂停"函数的执行,保存所有的状态,下次继续执行时从暂停的地方继续。

生成器函数

使用yield关键字定义的函数就是生成器函数:

python
def simple_generator():
yield 1
yield 2
yield 3

# 使用生成器
gen = simple_generator()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3

输出:

1
2
3

生成器函数的一个常见实现是斐波那契数列:

python
def fibonacci(n):
a, b = 0, 1
count = 0
while count < n:
yield a
a, b = b, a + b
count += 1

# 生成前10个斐波那契数
for num in fibonacci(10):
print(num, end=' ')

输出:

0 1 1 2 3 5 8 13 21 34 

生成器表达式

类似于列表推导式,Python也提供了生成器表达式,使用圆括号而不是方括号:

python
# 列表推导式
squares_list = [x**2 for x in range(5)] # 创建完整列表
print(squares_list)

# 生成器表达式
squares_gen = (x**2 for x in range(5)) # 创建生成器对象
for square in squares_gen:
print(square)

输出:

[0, 1, 4, 9, 16]
0
1
4
9
16
提示

生成器表达式比列表推导式更节省内存,特别是处理大型数据集时。生成器表达式不会一次性创建整个序列,而是按需生成每个元素。

迭代器与生成器的优势

内存效率

迭代器和生成器的最大优势之一是它们的内存效率。它们不需要一次性将所有数据加载到内存中,而是按需生成数据:

python
# 假设我们要处理一个大文件的每一行
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file: # 文件对象是一个迭代器
yield line.strip()

# 使用生成器处理文件,而不是一次性将整个文件读入内存
for line in read_large_file('example.txt'):
# 处理每一行...
pass

懒加载

迭代器实现了"懒加载"或"惰性求值",只在需要时才计算值:

python
def infinite_sequence():
num = 0
while True:
yield num
num += 1

# 虽然是"无限"序列,但我们只获取前5个
gen = infinite_sequence()
for _ in range(5):
print(next(gen))

输出:

0
1
2
3
4

链式操作

生成器可以进行链式操作,形成数据处理管道:

python
def numbers():
for i in range(1, 11):
yield i

def square(nums):
for num in nums:
yield num ** 2

def select_even(nums):
for num in nums:
if num % 2 == 0:
yield num

# 链式操作:生成1-10的数字,计算它们的平方,然后只选择偶数
pipeline = select_even(square(numbers()))
print(list(pipeline))

输出:

[4, 16, 36, 64, 100]

实际应用案例

分批处理数据

在处理大型数据集时,可以使用生成器分批处理数据:

python
def batch_processor(data, batch_size):
"""将数据分成固定大小的批次"""
for i in range(0, len(data), batch_size):
yield data[i:i + batch_size]

# 假设我们有一个大列表
large_data = list(range(1000))

# 每次处理100个元素
for batch in batch_processor(large_data, 100):
# 处理这一批数据
print(f"处理批次,大小: {len(batch)}")

输出:

处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100
处理批次,大小: 100

数据转换管道

创建数据转换管道,进行复杂的数据处理:

python
def read_data(file_path):
"""读取CSV文件数据"""
with open(file_path, 'r') as f:
next(f) # 跳过标题行
for line in f:
yield line.strip().split(',')

def parse_data(lines):
"""解析每行数据"""
for line in lines:
# 假设第一列是名字,第二列是年龄
yield {'name': line[0], 'age': int(line[1])}

def filter_adults(people):
"""只保留成年人"""
for person in people:
if person['age'] >= 18:
yield person

# 使用管道处理数据
# pipeline = filter_adults(parse_data(read_data('people.csv')))
# for person in pipeline:
# print(f"{person['name']} is {person['age']} years old")

无限数据流

创建无限数据流,适用于需要持续生成数据的场景:

python
import time
import random

def sensor_data_simulator():
"""模拟传感器数据流"""
while True:
# 生成随机温度数据
yield {
'timestamp': time.time(),
'temperature': round(random.uniform(20, 30), 2)
}
time.sleep(1) # 每秒生成一次数据

# 模拟读取5秒的传感器数据
sensor = sensor_data_simulator()
for _ in range(5):
data = next(sensor)
print(f"时间: {data['timestamp']}, 温度: {data['temperature']}°C")

输出示例:

时间: 1634567890.123, 温度: 24.57°C
时间: 1634567891.124, 温度: 22.31°C
时间: 1634567892.125, 温度: 25.84°C
时间: 1634567893.126, 温度: 21.47°C
时间: 1634567894.127, 温度: 28.09°C

高级迭代器工具

Python的itertools模块提供了许多用于创建和操作迭代器的函数:

python
import itertools

# 无限迭代器
count = itertools.count(10) # 从10开始计数
print([next(count) for _ in range(5)]) # [10, 11, 12, 13, 14]

# 循环迭代器
cycle = itertools.cycle(['A', 'B', 'C'])
print([next(cycle) for _ in range(7)]) # ['A', 'B', 'C', 'A', 'B', 'C', 'A']

# 组合迭代器
print(list(itertools.combinations([1, 2, 3, 4], 2))) # 所有可能的二元组合

输出:

[10, 11, 12, 13, 14]
['A', 'B', 'C', 'A', 'B', 'C', 'A']
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

生成器的高级特性

send 方法

生成器还有一个send()方法,它可以向生成器内部"发送"值:

python
def echo_generator():
value = yield "Ready"
print(f"Received: {value}")
while True:
value = yield value
print(f"Received: {value}")

gen = echo_generator()
print(next(gen)) # 启动生成器,打印"Ready"
print(gen.send("Hello")) # 发送"Hello"到生成器
print(gen.send(42)) # 发送42到生成器

输出:

Ready
Received: Hello
Hello
Received: 42
42

throw 和 close 方法

生成器还有throw()close()方法,用于抛出异常和关闭生成器:

python
def sample_generator():
try:
yield "First"
yield "Second"
yield "Third"
except Exception as e:
print(f"Exception caught: {e}")
yield "Exception handled"
finally:
print("Generator is closing")

gen = sample_generator()
print(next(gen)) # First
print(gen.throw(ValueError("Custom error"))) # 抛出一个异常到生成器内部
print(next(gen)) # Third
gen.close() # 关闭生成器

输出:

First
Exception caught: Custom error
Exception handled
Third
Generator is closing

总结

迭代器和生成器是Python中处理序列数据的强大工具。它们提供了内存效率高、处理能力强的解决方案,特别适合处理大型数据集或无限数据流。

主要优点包括:

  • 惰性求值,节省内存
  • 可以处理无限大的数据流
  • 代码简洁易读
  • 可以组合成数据处理管道
要点回顾
  • 迭代器是实现__iter__()__next__()方法的对象
  • 生成器是使用yield语句创建的特殊迭代器
  • 生成器表达式是创建生成器的简洁方法
  • itertools模块提供了丰富的迭代器工具

练习

为了巩固所学知识,尝试完成以下练习:

  1. 创建一个生成器,生成斐波那契数列的前N个数
  2. 编写一个自定义迭代器类,实现倒计时功能
  3. 使用生成器表达式找出1到1000中所有能被3和5同时整除的数
  4. 实现一个文件读取生成器,每次返回一个随机行
  5. 使用itertools模块中的函数生成所有可能的扑克牌组合

进一步学习资源

掌握迭代器和生成器可以帮助你编写更加高效、优雅的Python代码。随着你的Python编程能力的提升,这些工具将成为你解决复杂问题的重要武器!