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. 迭代器的优缺点

优点

  1. 内存高效:一次只保存一个元素
  2. 惰性求值:按需计算
  3. 无限序列:可以表示无限数据流
  4. 统一接口:所有可迭代对象都用相同方式遍历

缺点

  1. 只能遍历一次:迭代器是一次性的
  2. 不支持索引:不能iter[0]
  3. 不支持len():长度未知
  4. 调试困难:无法直接查看内容
 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. 创建一个迭代器,逆序生成1到n的数字
  2. 实现一个range_like迭代器,模仿range()的行为
  3. 用迭代器实现一个无限的素数生成器

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读