Python教程23:迭代器(Iterator)
“万变不离其宗。”
我们已经用过很多次for循环,但你知道它背后的机制吗?今天我们学习迭代器(Iterator)——Python迭代的核心协议。
1. 什么是迭代器
可迭代对象vs迭代器
可迭代对象(Iterable):
- 可以用
for循环遍历的对象 - 实现了
__iter__()方法 - 例如:列表、元组、字典、字符串、生成器
迭代器(Iterator):
- 实现了
__iter__()和__next__()方法的对象 - 可以被
next()函数调用 - 记住当前位置,可以逐个返回元素
关系:
- 所有迭代器都是可迭代对象
- 但不是所有可迭代对象都是迭代器
- 可迭代对象调用
iter()得到迭代器
1# 列表是可迭代对象,但不是迭代器
2my_list = [1, 2, 3]
3print(hasattr(my_list, '__iter__')) # True
4print(hasattr(my_list, '__next__')) # False
5
6# 获取迭代器
7iterator = iter(my_list)
8print(hasattr(iterator, '__iter__')) # True
9print(hasattr(iterator, '__next__')) # True
10
11# 使用迭代器
12print(next(iterator)) # 1
13print(next(iterator)) # 2
14print(next(iterator)) # 3
15# print(next(iterator)) # StopIteration
2. 迭代器协议
Python的迭代器协议包含两个方法:
iter()
返回迭代器对象本身:
1class MyIterator:
2 def __iter__(self):
3 return self # 返回自己
作用:
- 让对象可以用于
for循环 - 让对象可以调用
iter()
next()
返回下一个元素,没有元素时抛出StopIteration:
1class MyIterator:
2 def __next__(self):
3 # 返回下一个元素
4 # 或抛出StopIteration
5 pass
3. for循环的工作原理
for循环实际上是迭代器协议的语法糖:
1# for循环
2for item in my_list:
3 print(item)
4
5# 等价于
6iterator = iter(my_list) # 调用__iter__()
7while True:
8 try:
9 item = next(iterator) # 调用__next__()
10 print(item)
11 except StopIteration:
12 break
iter()和next()函数:
iter(obj):调用obj.__iter__()next(iterator):调用iterator.__next__()- 这些是Python内置函数(built-in functions)
4. 自定义迭代器
简单计数器
1class Counter:
2 """
3 自定义迭代器:计数器
4 - 从start计数到stop
5 - 实现__iter__和__next__
6 """
7 def __init__(self, start, stop):
8 self.current = start
9 self.stop = stop
10
11 def __iter__(self):
12 """返回迭代器对象(自己)"""
13 return self
14
15 def __next__(self):
16 """返回下一个值"""
17 if self.current >= self.stop:
18 raise StopIteration # 没有更多元素了
19
20 value = self.current
21 self.current += 1
22 return value
23
24# 使用
25counter = Counter(1, 5)
26for num in counter:
27 print(num, end=" ") # 1 2 3 4
斐波那契迭代器
1class Fibonacci:
2 """
3 斐波那契数列迭代器
4 - 可以指定生成多少个数
5 - 展示迭代器处理数学序列的能力
6 """
7 def __init__(self, n):
8 self.n = n # 生成n个数
9 self.count = 0
10 self.a, self.b = 0, 1
11
12 def __iter__(self):
13 return self
14
15 def __next__(self):
16 if self.count >= self.n:
17 raise StopIteration
18
19 value = self.a
20 self.a, self.b = self.b, self.a + self.b
21 self.count += 1
22 return value
23
24# 使用
25fib = Fibonacci(10)
26for num in fib:
27 print(num, end=" ")
28# 输出:0 1 1 2 3 5 8 13 21 34
5. 迭代器vs生成器
生成器是迭代器的一种简化实现:
1# 用迭代器类实现
2class CounterIterator:
3 def __init__(self, n):
4 self.n = n
5 self.current = 0
6
7 def __iter__(self):
8 return self
9
10 def __next__(self):
11 if self.current >= self.n:
12 raise StopIteration
13 value = self.current
14 self.current += 1
15 return value
16
17# 用生成器实现(更简洁)
18def counter_generator(n):
19 current = 0
20 while current < n:
21 yield current
22 current += 1
23
24# 两者效果相同
25for i in CounterIterator(5):
26 print(i)
27
28for i in counter_generator(5):
29 print(i)
何时用迭代器类:
- 需要复杂的状态管理
- 需要多个方法
- 需要继承或组合
何时用生成器:
- 逻辑简单
- 一次性使用
- 代码更简洁
6. 内置迭代器工具
iter()的第二种用法
iter()可以接收两个参数:
1# iter(callable, sentinel)
2# 重复调用callable,直到返回sentinel
3
4with open('data.txt') as f:
5 # 读取文件直到遇到空行
6 for line in iter(f.readline, '\n'):
7 print(line)
reversed()
反向迭代器:
1# reversed()返回反向迭代器
2# 来自Python内置函数
3my_list = [1, 2, 3, 4, 5]
4rev = reversed(my_list)
5
6print(type(rev)) # <class 'list_reverseiterator'>
7print(list(rev)) # [5, 4, 3, 2, 1]
enumerate()
带索引的迭代器:
1# enumerate()也返回迭代器
2# Python内置函数,用于同时获取索引和值
3fruits = ['apple', 'banana', 'cherry']
4enum = enumerate(fruits, start=1)
5
6print(type(enum)) # <class 'enumerate'>
7for i, fruit in enum:
8 print(f"{i}. {fruit}")
9# 1. apple
10# 2. banana
11# 3. cherry
zip()
并行迭代器:
1# zip()打包多个迭代器
2# Python内置函数,用于并行遍历
3names = ['Alice', 'Bob', 'Charlie']
4ages = [25, 30, 35]
5
6zipped = zip(names, ages)
7print(type(zipped)) # <class 'zip'>
8
9for name, age in zipped:
10 print(f"{name}: {age}")
7. itertools模块
Python标准库itertools提供了许多有用的迭代器:
1import itertools
2
3# itertools是Python标准库
4# 专门提供各种高效的迭代器工具
5
6# count:无限计数
7counter = itertools.count(start=10, step=2)
8for i in itertools.islice(counter, 5):
9 print(i) # 10, 12, 14, 16, 18
10
11# cycle:循环迭代
12colors = itertools.cycle(['red', 'green', 'blue'])
13for i, color in enumerate(colors):
14 if i >= 7:
15 break
16 print(color)
17
18# chain:连接迭代器
19chain = itertools.chain([1, 2], [3, 4], [5, 6])
20print(list(chain)) # [1, 2, 3, 4, 5, 6]
21
22# combinations:组合
23items = ['A', 'B', 'C']
24for combo in itertools.combinations(items, 2):
25 print(combo)
26# ('A', 'B')
27# ('A', 'C')
28# ('B', 'C')
8. 迭代器的优缺点
优点
- 内存高效:一次只保存一个元素
- 惰性求值:按需计算
- 无限序列:可以表示无限数据流
- 统一接口:所有可迭代对象都用相同方式遍历
缺点
- 只能遍历一次:迭代器是一次性的
- 不支持索引:不能
iter[0] - 不支持len():长度未知
- 调试困难:无法直接查看内容
1# 只能遍历一次
2it = iter([1, 2, 3])
3print(list(it)) # [1, 2, 3]
4print(list(it)) # [](已耗尽)
5
6# 不支持索引
7# print(it[0]) # TypeError
8
9# 不支持len()
10# print(len(it)) # TypeError
9. 实际应用
大文件处理
1def read_large_file(file_path):
2 """
3 迭代器方式读取大文件
4 - 一次读一行,不会把整个文件加载到内存
5 - 适合处理GB级别的日志文件
6 """
7 with open(file_path) as f:
8 for line in f: # 文件对象本身就是迭代器
9 yield line.strip()
10
11# 使用
12for line in read_large_file('huge_log.txt'):
13 if 'ERROR' in line:
14 print(line)
数据管道
1def numbers():
2 """生成数字"""
3 for i in range(100):
4 yield i
5
6def squares(nums):
7 """计算平方"""
8 for num in nums:
9 yield num ** 2
10
11def evens(nums):
12 """过滤偶数"""
13 for num in nums:
14 if num % 2 == 0:
15 yield num
16
17# 组合成管道
18pipeline = evens(squares(numbers()))
19print(list(itertools.islice(pipeline, 10)))
10. 小结
今天我们学习了迭代器:
- 定义:实现
__iter__和__next__的对象 - 协议:Python迭代的核心机制
- for循环:基于迭代器实现
- 自定义:创建自己的迭代器类
- vs生成器:生成器是特殊的迭代器
- 内置工具:iter、reversed、enumerate、zip
- itertools:标准库的迭代器集合
- 应用:大文件、数据管道
理解迭代器能让你更深入地理解Python的迭代机制。
练习题:
- 创建一个迭代器,逆序生成1到n的数字
- 实现一个range_like迭代器,模仿range()的行为
- 用迭代器实现一个无限的素数生成器
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
