一、迭代器(Iterator)
1. 迭代器简介
迭代器是一种可以记住遍历位置的对象。它实现了两个方法:
- __iter__():返回迭代器对象本身。
- __next__():返回下一个值,如果没有更多元素则抛出StopIteration异常。
迭代器是Python中处理可迭代对象的核心概念之一,广泛用于遍历数据结构如列表、元组、字典等。
2. 创建自定义迭代器
可以通过实现__iter__()和__next__()方法来创建自定义迭代器。
class MyIterator:
def __init__(self, data):
self.data = data # 存储要遍历的数据
self.index = 0 # 当前遍历的位置
def __iter__(self):
return self # 返回迭代器对象本身
def __next__(self):
if self.index < len(self.data): # 如果还有元素未遍历
result = self.data[self.index] # 获取当前元素
self.index += 1 # 更新索引
return result # 返回当前元素
else:
raise StopIteration # 没有更多元素时抛出异常
# 使用自定义迭代器
my_iterator = MyIterator([1, 2, 3, 4, 5])
for item in my_iterator:
print(item) # 输出 1, 2, 3, 4, 5
# 解释:
# - `MyIterator` 类实现了 `__iter__` 和 `__next__` 方法
# - `__iter__` 返回迭代器对象本身
# - `__next__` 返回下一个元素,直到没有更多元素时抛出 `StopIteration`
3. 内置函数iter()和next()
可以使用内置函数iter()和next()来手动操作迭代器。
numbers = [1, 2, 3, 4, 5]
iterator = iter(numbers) # 创建一个迭代器对象
print(next(iterator)) # 输出 1
print(next(iterator)) # 输出 2
print(next(iterator)) # 输出 3
# 解释:
# - `iter(numbers)` 将列表转换为迭代器对象
# - `next(iterator)` 获取迭代器的下一个元素
# - 当没有更多元素时会抛出 `StopIteration` 异常
4. 应用场景:文件读取
逐行读取大文件,避免一次性加载整个文件到内存中。
with open('large_file.txt', 'r') as file:
for line in file:
print(line.strip()) # 去除行末的换行符后打印
# 解释:
# - 文件对象本身是一个迭代器,每次迭代返回一行内容
# - `strip()` 方法去除行末的换行符和其他空白字符
# - 逐行读取文件内容,不会将整个文件加载到内存中
二、生成器(Generator)
1. 生成器简介
生成器是一种特殊的迭代器,使用yield语句代替return语句。生成器函数在每次调用next()时执行到yield语句,然后暂停并保存当前状态,直到下一次调用next()。
生成器非常适合处理大数据集或需要惰性求值的场景,因为它们不会一次性生成所有数据,而是按需生成。
2. 创建生成器
使用yield关键字创建生成器函数。
def my_generator():
yield 1 # 第一次调用 next() 时返回 1 并暂停
yield 2 # 第二次调用 next() 时返回 2 并暂停
yield 3 # 第三次调用 next() 时返回 3 并暂停
# 使用生成器
gen = my_generator()
print(next(gen)) # 输出 1
print(next(gen)) # 输出 2
print(next(gen)) # 输出 3
# 解释:
# - `my_generator` 是一个生成器函数
# - 每次调用 `next(gen)` 时,函数从上次暂停的地方继续执行
# - `yield` 关键字使函数暂停并返回一个值
3. 生成器表达式
类似于列表推导式,但返回的是一个生成器对象,而不是列表。生成器表达式非常节省内存。
# 生成器表达式
squares_gen = (x**2 for x in range(10))
# 按需打印生成的平方数
for square in squares_gen:
print(square)
# 解释:
# - `(x**2 for x in range(10))` 创建一个生成器对象
# - 每次迭代时计算下一个平方数,而不是一次性生成所有平方数
# - 生成器表达式比列表推导式更节省内存
4. 应用场景:节省内存
处理大数据集时避免占用过多内存。
# 示例:计算大数据集的总和
large_range = (x for x in range(10**6))
total = sum(large_range)
print(total) # 输出 499999500000
# 解释:
# - `(x for x in range(10**6))` 创建一个生成器对象
# - `sum(large_range)` 计算生成器对象中所有元素的总和
# - 生成器对象不会一次性加载所有元素到内存中,而是按需生成
5. 应用场景:惰性求值
生成器支持惰性求值,即只在需要时才计算值。这在处理无限序列或昂贵计算时特别有用。
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# 使用生成器惰性求值
fib = fibonacci(10)
for num in fib:
print(num)
# 解释:
# - `fibonacci` 函数是一个生成器函数
# - 每次调用 `next(fib)` 时计算下一个斐波那契数
# - 只在需要时计算值,避免不必要的计算
6. 应用场景:无限序列
生成器可以用于生成无限序列,适合模拟流数据或其他无边界的数据源。
def infinite_sequence():
num = 0
while True:
yield num
num += 1
# 使用无限序列生成器
seq = infinite_sequence()
# 打印前 10 个元素
for i in range(10):
print(next(seq))
# 解释:
# - `infinite_sequence` 是一个生成器函数,生成无限序列
# - 每次调用 `next(seq)` 时返回下一个数字
# - 无限序列生成器可以在需要时不断生成新值
7. 应用场景:管道处理
生成器可以与其他生成器或函数组合,形成数据处理管道,简化复杂的数据处理流程。
def filter_even(numbers):
for num in numbers:
if num % 2 == 0:
yield num
def square_numbers(numbers):
for num in numbers:
yield num ** 2
# 创建数据处理管道
numbers = range(10)
even_numbers = filter_even(numbers)
squared_even_numbers = square_numbers(even_numbers)
# 打印结果
for num in squared_even_numbers:
print(num)
# 解释:
# - `filter_even` 生成器过滤偶数
# - `square_numbers` 生成器计算平方
# - 数据处理管道将多个生成器串联起来,简化代码逻辑
三、总结
迭代器和生成器是Python中处理可迭代对象的核心工具,提供了高效且简洁的方式来遍历数据。它们的主要特点包括:
- 迭代器:实现了__iter__()和__next__()方法,可以记住遍历位置。
- 生成器:使用yield语句创建,支持惰性求值和节省内存。
这些工具广泛应用于各种编程场景中,例如:
- 文件读取:逐行读取大文件,避免一次性加载整个文件到内存中。
- 节省内存:处理大数据集时避免占用过多内存。
- 惰性求值:只在需要时计算值,避免不必要的计算。
- 无限序列:生成无限序列,适合模拟流数据或其他无边界的数据源。
- 管道处理:简化复杂的数据处理流程。