Python进阶--迭代器

一、迭代器基础入门

1.1 核心概念:迭代、可迭代对象、迭代器

1.1.1 什么是迭代?

迭代就是重复执行某个操作,依次获取序列/集合中的每一个元素 的过程。我们最常用的for...in...循环遍历数据的过程,本质就是迭代。

复制代码
# 最常见的迭代:for循环遍历列表
nums = [1, 2, 3, 4, 5]
# 迭代过程:依次取出nums中的每个元素,赋值给num,执行循环体
for num in nums:
    print(num)

# 输出:
# 1
# 2
# 3
# 4
# 5

注意:不是所有对象都能被迭代,比如数字int、浮点数float就无法被for循环遍历,会直接报错。

复制代码
# 错误示例:非可迭代对象无法被迭代
weight = 160
for item in weight:
    print(item)
# 报错:TypeError: 'int' object is not iterable
1.1.2 可迭代对象(Iterable)

通俗定义 :凡是能被for...in...循环遍历的对象,都是可迭代对象。
官方定义 :实现了__iter__()魔法方法的对象,就是可迭代对象。

Python中常见的可迭代对象:

  • 序列类型:列表list、元组tuple、字符串str
  • 集合类型:集合set、字典dict
  • 文件对象:open()打开的文件句柄
  • 特殊对象:range()对象、map/filter/zip等函数返回的对象
1.1.3 迭代器(Iterator)

通俗定义 :一个能记住遍历位置 的智能书签,它可以逐个返回序列中的元素,直到所有元素遍历完毕。
官方定义 :同时实现了__iter__()__next__()两个魔法方法的对象,就是迭代器,这两个方法合称为迭代器协议

1.1.4 三者核心区别对比表

|--------------------|---------------------|---------------------------|
| 特性 | 可迭代对象 | 迭代器 |
| 必须实现__iter__()方法 | ✅ 是 | ✅ 是 |
| 必须实现__next__()方法 | ❌ 否 | ✅ 是 |
| 能被for循环遍历 | ✅ 是 | ✅ 是 |
| 能用next()函数获取元素 | ❌ 否(需先转迭代器) | ✅ 是 |
| 可多次遍历 | ✅ 是(每次遍历生成新迭代器) | ❌ 否(一次性,遍历完即耗尽) |
| 内存占用 | 一次性加载所有元素 | 惰性加载,仅生成当前元素 |
| 常见示例 | list、str、dict、tuple | iter(list)、map、filter、zip |

1.1.5 核心关系

可迭代对象 → 调用iter()函数 → 生成迭代器 → 调用next()函数 → 逐个获取元素


1.2 for循环的底层原理(迭代的本质)

我们天天用的for循环,底层完全是基于迭代器实现的,它的执行流程可以拆解为以下4步:

  1. 调用iter(可迭代对象),获取该对象的迭代器;
  2. 循环调用next(迭代器),依次获取下一个元素;
  3. 成功获取元素后,执行循环体;
  4. 当没有更多元素时,捕获StopIteration异常,结束循环。

我们用代码完全复刻for循环的底层执行逻辑:

复制代码
# 原始for循环
nums = [10, 20, 30]
print("原始for循环执行结果:")
for num in nums:
    print(num)

# 复刻for循环的底层实现
print("\n复刻for循环底层逻辑执行结果:")
# 1. 调用iter()获取列表的迭代器
nums_iterator = iter(nums)
while True:
    try:
        # 2. 循环调用next()获取下一个元素
        num = next(nums_iterator)
        # 3. 执行循环体
        print(num)
    except StopIteration:
        # 4. 捕获异常,结束循环
        break

# 两段代码输出完全一致

1.3 核心内置函数:iter() 与 next()

这两个函数是操作迭代器的核心,所有迭代操作都基于这两个函数实现。

1.3.1 iter() 函数:将可迭代对象转为迭代器

语法iter(iterable)
核心作用 :接收一个可迭代对象,返回该对象对应的迭代器;如果传入的不是可迭代对象,直接抛出TypeError
完整代码示例

复制代码
import re
def test_iter_function():
    """测试iter()函数的完整用法"""
    print("========== iter()函数测试 ==========")
    
    # 1. 列表(可迭代对象)转迭代器
    list1 = [1, 2, 3]
    list_iter = iter(list1)
    print(f"1. 列表转迭代器:{list_iter}")
    print(f"   迭代器类型:{type(list_iter)}")
    
    # 2. 字符串转迭代器
    str1 = "python"
    str_iter = iter(str1)
    print(f"\n2. 字符串转迭代器:{str_iter}")
    
    # 3. 字典转迭代器(默认迭代key)
    dict1 = {"name": "张三", "age": 20}
    dict_iter = iter(dict1)
    print(f"\n3. 字典转迭代器,第一个元素:{next(dict_iter)}")
    
    # 4. 非可迭代对象调用iter()会报错
    try:
        int1 = 123
        int_iter = iter(int1)
    except TypeError as e:
        print(f"\n4. 非可迭代对象报错:{e}")

# 运行测试
test_iter_function()
1.3.2 next() 函数:获取迭代器的下一个元素

语法next(iterator, default=None)
核心作用 :接收一个迭代器,返回迭代器的下一个元素;如果迭代器没有更多元素,有默认值则返回默认值,无默认值则抛出StopIteration异常。
完整代码示例

复制代码
def test_next_function():
    """测试next()函数的完整用法"""
    print("\n========== next()函数测试 ==========")
    
    # 1. 基础用法:逐个获取迭代器元素
    nums = [10, 20, 30]
    nums_iter = iter(nums)
    print("1. 基础用法:逐个获取元素")
    print(f"   第一次next:{next(nums_iter)}")
    print(f"   第二次next:{next(nums_iter)}")
    print(f"   第三次next:{next(nums_iter)}")
    
    # 2. 无元素时,无默认值会抛出StopIteration
    print("\n2. 无元素无默认值的情况")
    try:
        next(nums_iter)  # 已经没有元素了
    except StopIteration as e:
        print(f"   抛出异常:{e}")
    
    # 3. 无元素时,设置默认值不会报错,返回默认值
    print("\n3. 无元素有默认值的情况")
    nums_iter2 = iter([1, 2])
    next(nums_iter2)
    next(nums_iter2)
    # 已经没有元素,设置默认值"无更多元素"
    print(f"   带默认值的next:{next(nums_iter2, '无更多元素')}")

# 运行测试
test_next_function()

二、迭代器核心协议(魔法方法详解)

迭代器的核心是迭代器协议 ,它规定了一个对象要成为迭代器,必须实现两个魔法方法:__iter__()__next__(),缺一不可。

2.1 iter() 方法

语法def __iter__(self):
核心要求 :必须返回一个迭代器对象(通常返回self,也就是对象本身)
核心作用

  1. 告诉Python解释器,这个对象是可迭代的;
  2. for循环、iter()函数会自动调用这个方法,获取迭代器。

2.2 next() 方法

语法def __next__(self):
核心要求

  1. 必须返回迭代器的下一个元素;
  2. 当没有更多元素时,必须主动抛出StopIteration异常,终止迭代。
    核心作用:控制迭代的逻辑,记录遍历位置,生成/返回下一个元素,处理迭代终止条件。

2.3 StopIteration 异常

这是迭代终止的唯一标准信号,Python的for循环、迭代相关函数都会自动捕获这个异常来结束迭代,无需我们手动处理。

注意:自定义迭代器时,必须在没有元素时主动抛出这个异常,否则会陷入无限循环!

2.4 核心协议完整代码示例

复制代码
class SimpleIterator:
    """一个最简单的、符合迭代器协议的自定义迭代器"""
    def __init__(self, end_num):
        # 初始化:设置迭代的终止数字
        self.end_num = end_num
        # 记录当前遍历的位置,初始值为0
        self.current = 0

    def __iter__(self):
        """必须实现的__iter__方法,返回迭代器本身"""
        print("调用了__iter__方法")
        return self

    def __next__(self):
        """必须实现的__next__方法,返回下一个元素,无元素时抛异常"""
        print("调用了__next__方法")
        # 终止条件:当前数字 >= 终止数字时,抛异常结束迭代
        if self.current >= self.end_num:
            raise StopIteration
        # 记录当前要返回的值
        return_value = self.current
        # 位置+1,为下一次迭代做准备
        self.current += 1
        # 返回当前值
        return return_value

# 测试自定义迭代器
if __name__ == "__main__":
    print("========== 迭代器协议测试 ==========")
    # 创建迭代器实例,终止数字为3
    my_iter = SimpleIterator(3)
    
    # 1. 用for循环遍历(自动调用__iter__和__next__)
    print("1. for循环遍历迭代器:")
    for num in my_iter:
        print(f"   迭代到:{num}")
    
    # 2. 手动用iter()和next()遍历
    print("\n2. 手动调用iter()和next():")
    my_iter2 = SimpleIterator(2)
    # iter()会自动调用__iter__方法
    iter_obj = iter(my_iter2)
    # next()会自动调用__next__方法
    print(f"   第一次next:{next(iter_obj)}")
    print(f"   第二次next:{next(iter_obj)}")
    # 第三次next会抛异常
    try:
        next(iter_obj)
    except StopIteration:
        print(f"   第三次next:抛出StopIteration异常,迭代结束")

三、自定义迭代器(从入门到实战)

通过实现迭代器协议,我们可以自定义任意逻辑的迭代器,下面从简单到复杂,提供3个完整的自定义迭代器案例,覆盖绝大多数实战场景。

3.1 基础案例:自定义range迭代器

模拟Python内置的range()函数,实现一个自定义的数字序列迭代器,支持起始值、终止值、步长。

复制代码
class MyRange:
    """自定义range迭代器,支持start、end、step"""
    def __init__(self, start, end=None, step=1):
        """
        初始化方法
        :param start: 起始值
        :param end: 终止值(可选,不填则start为0,end为传入的start)
        :param step: 步长,默认1,不能为0
        """
        # 处理只传一个参数的情况,比如MyRange(5) 等价于 MyRange(0,5)
        if end is None:
            self.start = 0
            self.end = start
        else:
            self.start = start
            self.end = end
        # 步长校验
        if step == 0:
            raise ValueError("步长不能为0")
        self.step = step
        # 记录当前位置,初始值为start
        self.current = self.start

    def __iter__(self):
        """返回迭代器本身,符合迭代器协议"""
        return self

    def __next__(self):
        """核心迭代逻辑,控制步长和终止条件"""
        # 终止条件:正步长时,current >= end 终止;负步长时,current <= end 终止
        if (self.step > 0 and self.current >= self.end) or (self.step < 0 and self.current <= self.end):
            raise StopIteration
        # 记录要返回的值
        return_value = self.current
        # 按步长更新当前位置
        self.current += self.step
        # 返回值
        return return_value

# 测试自定义MyRange迭代器
if __name__ == "__main__":
    print("========== 自定义MyRange迭代器测试 ==========")
    
    # 1. 只传终止值
    print("1. MyRange(5):")
    for num in MyRange(5):
        print(f"   {num}", end=" ")
    print()
    
    # 2. 传起始值和终止值
    print("\n2. MyRange(2, 8):")
    for num in MyRange(2, 8):
        print(f"   {num}", end=" ")
    print()
    
    # 3. 传起始值、终止值、步长
    print("\n3. MyRange(1, 10, 2):")
    for num in MyRange(1, 10, 2):
        print(f"   {num}", end=" ")
    print()
    
    # 4. 负步长(倒序)
    print("\n4. MyRange(10, 0, -2):")
    for num in MyRange(10, 0, -2):
        print(f"   {num}", end=" ")
    print()

3.2 进阶案例:斐波那契数列迭代器

实现一个斐波那契数列迭代器,支持指定最大生成个数,完美体现迭代器惰性计算的核心优势(无需一次性生成所有数列,用的时候才生成)。

复制代码
class FibonacciIterator:
    """斐波那契数列迭代器"""
    def __init__(self, max_count):
        """
        初始化方法
        :param max_count: 要生成的斐波那契数列的最大个数
        """
        self.max_count = max_count  # 最大生成个数
        self.count = 0  # 记录已经生成的个数
        # 斐波那契初始值:a=第0个数,b=第1个数
        self.a, self.b = 0, 1

    def __iter__(self):
        """返回迭代器本身"""
        return self

    def __next__(self):
        """生成下一个斐波那契数"""
        # 终止条件:生成个数达到最大值
        if self.count >= self.max_count:
            raise StopIteration
        # 记录当前要返回的数
        current_num = self.a
        # 更新斐波那契数列:a变成b,b变成a+b
        self.a, self.b = self.b, self.a + self.b
        # 生成个数+1
        self.count += 1
        # 返回当前数
        return current_num

# 测试斐波那契迭代器
if __name__ == "__main__":
    print("========== 斐波那契数列迭代器测试 ==========")
    # 生成前10个斐波那契数
    fib_iter = FibonacciIterator(10)
    print("前10个斐波那契数:")
    for num in fib_iter:
        print(f"   {num}", end=" ")
    print()
    
    # 手动逐个获取,体现惰性计算
    print("\n手动逐个获取前3个斐波那契数:")
    fib_iter2 = FibonacciIterator(10)
    print(f"   第1个:{next(fib_iter2)}")
    print(f"   第2个:{next(fib_iter2)}")
    print(f"   第3个:{next(fib_iter2)}")

3.3 高级案例:可迭代对象与迭代器分离

前面的案例中,一个类同时是可迭代对象和迭代器,会导致无法多次遍历 的问题。实战中更规范的写法是:将可迭代对象和迭代器拆分为两个类 ,每次调用__iter__()都返回一个新的迭代器实例,实现多次遍历。

复制代码
# 1. 迭代器类:只负责迭代逻辑,实现__iter__和__next__
class StudentIterator:
    """学生列表迭代器,负责具体的迭代逻辑"""
    def __init__(self, student_list):
        self.student_list = student_list
        self.index = 0  # 记录遍历的索引位置

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.student_list):
            raise StopIteration
        # 获取当前索引的学生
        current_student = self.student_list[self.index]
        # 索引+1
        self.index += 1
        # 返回学生信息
        return current_student

# 2. 可迭代对象类:只负责生成迭代器,实现__iter__
class StudentList:
    """学生列表可迭代对象,对外暴露,支持多次遍历"""
    def __init__(self):
        self.students = ["张三", "李四", "王五", "赵六"]

    def __iter__(self):
        """每次调用都返回一个全新的迭代器实例,实现多次遍历"""
        return StudentIterator(self.students)

# 测试可迭代对象与迭代器分离的实现
if __name__ == "__main__":
    print("========== 可迭代对象与迭代器分离测试 ==========")
    # 创建可迭代对象
    student_list = StudentList()
    
    # 第一次遍历
    print("第一次遍历学生列表:")
    for student in student_list:
        print(f"   {student}")
    
    # 第二次遍历(完全正常,因为每次for循环都会生成新的迭代器)
    print("\n第二次遍历学生列表:")
    for student in student_list:
        print(f"   {student}")
    
    # 对比:之前的合并写法,遍历一次后就无法再次遍历
    print("\n对比:合并写法的迭代器无法多次遍历")
    fib_iter = FibonacciIterator(3)
    print("第一次遍历:")
    for num in fib_iter:
        print(f"   {num}")
    print("第二次遍历:无任何输出,迭代器已耗尽")
    for num in fib_iter:
        print(f"   {num}")

四、迭代器的核心特性与优缺点

4.1 核心特性1:惰性计算(最核心优势)

惰性计算 :迭代器不会一次性生成所有元素,只有当调用next()函数时,才会生成并返回下一个元素。
核心优势:极大节省内存,即使处理无限大的数据集,也只会占用极小的内存空间。

我们用代码对比列表和迭代器的内存占用差异:

复制代码
import sys

def test_lazy_compute():
    """测试迭代器的惰性计算与内存优势"""
    print("========== 惰性计算与内存占用测试 ==========")
    
    # 1. 列表:一次性生成100万个数字,全部加载到内存
    list_nums = [i for i in range(1000000)]
    # 查看列表占用的内存大小(字节)
    list_memory = sys.getsizeof(list_nums)
    print(f"1. 包含100万个元素的列表内存占用:{list_memory / 1024 / 1024:.2f} MB")
    
    # 2. 迭代器:仅生成迭代器对象,不生成任何元素,调用next()时才生成
    iter_nums = iter(range(1000000))
    # 查看迭代器占用的内存大小(字节)
    iter_memory = sys.getsizeof(iter_nums)
    print(f"2. 对应迭代器的内存占用:{iter_memory} 字节")
    
    print(f"\n内存差距:{list_memory // iter_memory} 倍以上!")

# 运行测试
test_lazy_compute()

4.2 核心特性2:一次性遍历(单向不可重置)

迭代器只能单向前进、不能后退,遍历完一次之后,迭代器就被"耗尽"了,无法再次遍历,必须重新生成新的迭代器才能再次遍历。

复制代码
def test_one_time_iter():
    """测试迭代器的一次性遍历特性"""
    print("\n========== 一次性遍历特性测试 ==========")
    
    # 1. 列表(可迭代对象):可多次遍历
    nums = [1, 2, 3]
    print("1. 列表可多次遍历:")
    print(f"   第一次遍历:{[i for i in nums]}")
    print(f"   第二次遍历:{[i for i in nums]}")
    
    # 2. 迭代器:只能遍历一次,第二次无输出
    nums_iter = iter(nums)
    print("\n2. 迭代器只能遍历一次:")
    print(f"   第一次遍历:{[i for i in nums_iter]}")
    print(f"   第二次遍历:{[i for i in nums_iter]}(空列表,迭代器已耗尽)")
    
    # 3. 解决办法:重新生成迭代器
    print("\n3. 重新生成迭代器即可再次遍历:")
    nums_iter2 = iter(nums)
    print(f"   新迭代器遍历:{[i for i in nums_iter2]}")

# 运行测试
test_one_time_iter()

4.3 核心特性3:支持无限序列

因为惰性计算的特性,迭代器可以表示一个无限长的序列,而列表永远无法存储无限多的元素。

复制代码
class InfiniteNumber:
    """无限递增的数字迭代器"""
    def __init__(self, start=0, step=1):
        self.current = start
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        return_value = self.current
        self.current += self.step
        return return_value

# 测试无限迭代器
if __name__ == "__main__":
    print("\n========== 无限序列迭代器测试 ==========")
    # 创建无限迭代器,从1开始,步长2(奇数序列)
    infinite_iter = InfiniteNumber(1, 2)
    
    # 只取前5个元素,不会无限生成
    print("无限奇数序列的前5个元素:")
    for _ in range(5):
        print(f"   {next(infinite_iter)}")
    
    # 继续取,会接着之前的位置继续生成
    print("\n继续取接下来的3个元素:")
    for _ in range(3):
        print(f"   {next(infinite_iter)}")

4.4 迭代器的优缺点总结

|-------------------------|--------------------|
| 优点 | 缺点 |
| 内存占用极低,惰性计算,适合处理大数据/大文件 | 一次性遍历,无法重复使用,需重新生成 |
| 支持无限序列,突破内存限制 | 无法随机访问元素,只能按顺序逐个获取 |
| 代码解耦,迭代逻辑与业务逻辑分离 | 无法获取长度,不能用len()函数 |
| 可组合使用,构建数据处理流水线 | 遍历过程中无法回退,只能单向前进 |


五、Python内置的可迭代对象与迭代器

5.1 常见的内置可迭代对象

Python中绝大多数容器类型都是可迭代对象,我们可以用iter()将它们转为迭代器,用next()逐个获取元素。

复制代码
def test_builtin_iterable():
    """测试Python内置的可迭代对象"""
    print("========== 内置可迭代对象测试 ==========")
    
    # 1. 字符串
    print("1. 字符串迭代器:")
    str_iter = iter("python")
    print(f"   第一个字符:{next(str_iter)}")
    print(f"   第二个字符:{next(str_iter)}")
    
    # 2. 元组
    print("\n2. 元组迭代器:")
    tuple_iter = iter((10, 20, 30))
    print(f"   第一个元素:{next(tuple_iter)}")
    
    # 3. 字典:默认迭代key,也可以迭代value、键值对
    print("\n3. 字典迭代器:")
    dict1 = {"name": "张三", "age": 20}
    # 迭代key
    key_iter = iter(dict1)
    print(f"   迭代key:{next(key_iter)}")
    # 迭代value
    value_iter = iter(dict1.values())
    print(f"   迭代value:{next(value_iter)}")
    # 迭代键值对
    item_iter = iter(dict1.items())
    print(f"   迭代键值对:{next(item_iter)}")
    
    # 4. 集合
    print("\n4. 集合迭代器:")
    set_iter = iter({1, 2, 3})
    print(f"   第一个元素:{next(set_iter)}")
    
    # 5. range对象
    print("\n5. range对象迭代器:")
    range_iter = iter(range(3))
    print(f"   第一个元素:{next(range_iter)}")
    
    # 6. 文件对象:本身就是迭代器
    print("\n6. 文件对象(本身就是迭代器):")
    # 打开文件,文件句柄本身就是迭代器,逐行迭代
    with open("test.txt", "w", encoding="utf-8") as f:
        f.write("第一行\n第二行\n第三行")
    with open("test.txt", "r", encoding="utf-8") as f:
        print(f"   第一行:{next(f).strip()}")
        print(f"   第二行:{next(f).strip()}")

# 运行测试
test_builtin_iterable()

5.2 内置函数返回的迭代器

Python中很多内置函数返回的都是迭代器,而非列表,这是为了节省内存,常用的有map()filter()zip()enumerate()

复制代码
def test_builtin_iterator_func():
    """测试返回迭代器的内置函数"""
    print("\n========== 内置迭代器函数测试 ==========")
    
    nums = [1, 2, 3, 4, 5]
    strs = ["a", "b", "c"]
    
    # 1. map():对可迭代对象的每个元素执行函数,返回迭代器
    print("1. map()函数(返回迭代器):")
    map_iter = map(lambda x: x * 2, nums)
    print(f"   map返回的类型:{type(map_iter)}")
    print(f"   迭代器内容:{list(map_iter)}")
    
    # 2. filter():过滤符合条件的元素,返回迭代器
    print("\n2. filter()函数(返回迭代器):")
    filter_iter = filter(lambda x: x % 2 == 0, nums)
    print(f"   filter返回的类型:{type(filter_iter)}")
    print(f"   迭代器内容:{list(filter_iter)}")
    
    # 3. zip():将多个可迭代对象按位置配对,返回迭代器
    print("\n3. zip()函数(返回迭代器):")
    zip_iter = zip(nums, strs)
    print(f"   zip返回的类型:{type(zip_iter)}")
    print(f"   迭代器内容:{list(zip_iter)}")
    
    # 4. enumerate():为元素添加索引,返回迭代器
    print("\n4. enumerate()函数(返回迭代器):")
    enum_iter = enumerate(strs, start=1)
    print(f"   enumerate返回的类型:{type(enum_iter)}")
    print(f"   迭代器内容:{list(enum_iter)}")
    
    # 重点:这些函数返回的迭代器,只能遍历一次
    print("\n重点:迭代器只能遍历一次")
    map_iter2 = map(lambda x: x*2, nums)
    print(f"   第一次转列表:{list(map_iter2)}")
    print(f"   第二次转列表:{list(map_iter2)}(空列表,已耗尽)")

# 运行测试
test_builtin_iterator_func()

六、迭代器进阶:itertools 高效迭代器工具库

itertools是Python内置的迭代器工具库,提供了大量高效、简洁的迭代器创建函数,专门用于处理迭代操作,所有函数返回的都是迭代器,完美契合惰性计算的特性,是Python迭代器实战的必备工具。

6.1 无限迭代器

生成无限序列的迭代器,需配合终止条件使用,避免无限循环。

复制代码
import itertools

def test_itertools_infinite():
    """测试itertools无限迭代器"""
    print("========== itertools 无限迭代器 ==========")
    
    # 1. count(start, step):从start开始,按step步长无限递增
    print("\n1. count() 无限递增序列:")
    count_iter = itertools.count(start=1, step=2)  # 奇数序列
    print("   前5个元素:", end="")
    for _ in range(5):
        print(next(count_iter), end=" ")
    print()
    
    # 2. cycle(iterable):无限循环遍历可迭代对象的元素
    print("\n2. cycle() 无限循环序列:")
    cycle_iter = itertools.cycle(["A", "B", "C"])
    print("   前6个元素:", end="")
    for _ in range(6):
        print(next(cycle_iter), end=" ")
    print()
    
    # 3. repeat(obj, times):重复生成指定对象,times不指定则无限重复
    print("\n3. repeat() 重复对象:")
    repeat_iter = itertools.repeat(10, times=3)
    print("   重复3次10:", list(repeat_iter))

# 运行测试
test_itertools_infinite()

6.2 有限迭代器

常用的有限序列迭代器,用于过滤、切片、拼接、累积等操作。

复制代码
import itertools

def test_itertools_limited():
    """测试itertools有限迭代器"""
    print("\n========== itertools 有限迭代器 ==========")
    
    nums = [1, 2, 3, 4, 5, 6]
    strs = ["A", "B", "C", "D"]
    
    # 1. chain(*iterables):拼接多个可迭代对象,返回一个连续的迭代器
    print("\n1. chain() 拼接多个可迭代对象:")
    chain_iter = itertools.chain(nums, strs)
    print(f"   拼接结果:{list(chain_iter)}")
    
    # 2. islice(iterable, start, stop, step):对迭代器切片,不支持负索引
    print("\n2. islice() 迭代器切片:")
    islice_iter = itertools.islice(nums, 1, 5, 2)  # 从索引1到5,步长2
    print(f"   切片结果:{list(islice_iter)}")
    
    # 3. accumulate(iterable, func):累积计算,默认累加
    print("\n3. accumulate() 累积计算:")
    acc_iter = itertools.accumulate(nums)
    print(f"   累加结果:{list(acc_iter)}")
    # 自定义累积:累乘
    acc_mult_iter = itertools.accumulate(nums, lambda x,y: x*y)
    print(f"   累乘结果:{list(acc_mult_iter)}")
    
    # 4. takewhile(predicate, iterable):只要条件为True就取元素,条件为False立即停止
    print("\n4. takewhile() 按条件取元素:")
    take_iter = itertools.takewhile(lambda x: x < 4, nums)
    print(f"   小于4的元素:{list(take_iter)}")
    
    # 5. dropwhile(predicate, iterable):丢弃前面符合条件的元素,条件为False开始保留
    print("\n5. dropwhile() 按条件丢弃元素:")
    drop_iter = itertools.dropwhile(lambda x: x < 4, nums)
    print(f"   丢弃小于4的元素后:{list(drop_iter)}")
    
    # 6. filterfalse(predicate, iterable):反向过滤,保留条件为False的元素
    print("\n6. filterfalse() 反向过滤:")
    filter_iter = itertools.filterfalse(lambda x: x % 2 == 0, nums)
    print(f"   保留奇数:{list(filter_iter)}")

# 运行测试
test_itertools_limited()

6.3 组合迭代器

用于生成排列、组合、笛卡尔积等组合序列的迭代器,是算法、数据分析的常用工具。

复制代码
import itertools

def test_itertools_combine():
    """测试itertools组合迭代器"""
    print("\n========== itertools 组合迭代器 ==========")
    
    letters = ["A", "B", "C"]
    
    # 1. product(*iterables, repeat):生成笛卡尔积,替代嵌套for循环
    print("\n1. product() 笛卡尔积:")
    product_iter = itertools.product(letters, [1, 2])
    print(f"   笛卡尔积结果:{list(product_iter)}")
    
    # 2. permutations(iterable, r):生成长度为r的全排列(顺序有关)
    print("\n2. permutations() 全排列:")
    perm_iter = itertools.permutations(letters, r=2)
    print(f"   2个元素的全排列:{list(perm_iter)}")
    
    # 3. combinations(iterable, r):生成长度为r的组合(顺序无关,不重复)
    print("\n3. combinations() 组合:")
    comb_iter = itertools.combinations(letters, r=2)
    print(f"   2个元素的组合:{list(comb_iter)}")
    
    # 4. combinations_with_replacement():允许重复元素的组合
    print("\n4. combinations_with_replacement() 可重复组合:")
    comb_rep_iter = itertools.combinations_with_replacement(letters, r=2)
    print(f"   可重复组合:{list(comb_rep_iter)}")

# 运行测试
test_itertools_combine()

七、迭代器与生成器的区别与联系

很多新手会混淆迭代器和生成器,这里明确两者的核心关系与区别,配有完整代码对比。

7.1 核心关系:生成器是特殊的迭代器

生成器(Generator)是Python提供的一种更简洁的创建迭代器的方式,它完全符合迭代器协议,本质上就是一个迭代器。

  • 生成器有两种创建方式:
    1. 生成器表达式:(i for i in range(10))
    2. 生成器函数:使用yield关键字的函数

7.2 迭代器与生成器的核心区别

|-------|-------------------------------|-----------------------|
| 对比维度 | 迭代器 | 生成器 |
| 创建方式 | 定义类,实现__iter____next__方法 | 生成器表达式、带yield的函数 |
| 代码复杂度 | 代码量多,逻辑复杂,需手动维护状态和异常 | 代码简洁,无需手动维护状态和异常 |
| 状态管理 | 需手动在类中定义属性记录遍历位置 | Python自动保存执行状态,无需手动管理 |
| 异常处理 | 需手动抛出StopIteration异常 | 自动处理,函数执行完毕自动抛出异常 |
| 适用场景 | 复杂的迭代逻辑、自定义迭代行为 | 简单的迭代逻辑、快速创建迭代器 |

7.3 代码对比:迭代器 vs 生成器

同样实现一个0-3的数字序列,对比迭代器和生成器的实现差异:

复制代码
# 方式1:自定义迭代器实现
class NumberIterator:
    def __init__(self, end):
        self.current = 0
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        return_value = self.current
        self.current += 1
        return return_value

# 方式2:生成器函数实现
def number_generator(end):
    current = 0
    while current < end:
        # yield关键字:返回当前值,暂停函数执行,下次next()从这里继续
        yield current
        current += 1

# 方式3:生成器表达式实现
number_gen_expr = (i for i in range(3))

# 测试三者效果完全一致
if __name__ == "__main__":
    print("========== 迭代器 vs 生成器 对比测试 ==========")
    
    # 1. 自定义迭代器
    print("1. 自定义迭代器:")
    iter1 = NumberIterator(3)
    for num in iter1:
        print(f"   {num}", end=" ")
    print()
    
    # 2. 生成器函数
    print("\n2. 生成器函数:")
    gen1 = number_generator(3)
    for num in gen1:
        print(f"   {num}", end=" ")
    print()
    
    # 3. 生成器表达式
    print("\n3. 生成器表达式:")
    gen2 = number_gen_expr
    for num in gen2:
        print(f"   {num}", end=" ")
    print()
    
    # 验证生成器本质是迭代器
    gen3 = number_generator(3)
    print(f"\n生成器是否是迭代器:")
    print(f"   有__iter__方法:{hasattr(gen3, '__iter__')}")
    print(f"   有__next__方法:{hasattr(gen3, '__next__')}")
    print(f"   能用next()调用:{next(gen3)}")

八、新手避坑指南(高频错误+代码对比)

坑1:迭代器遍历耗尽后,无法再次遍历

错误代码

复制代码
nums = [1,2,3]
nums_iter = iter(nums)
# 第一次遍历
print("第一次遍历:", list(nums_iter))
# 第二次遍历,无任何输出,迭代器已耗尽
print("第二次遍历:", list(nums_iter))

正确代码:每次需要遍历时,重新生成迭代器

复制代码
nums = [1,2,3]
# 第一次遍历
nums_iter1 = iter(nums)
print("第一次遍历:", list(nums_iter1))
# 第二次遍历,重新生成迭代器
nums_iter2 = iter(nums)
print("第二次遍历:", list(nums_iter2))

坑2:混淆可迭代对象和迭代器,对可迭代对象调用next()

错误代码

复制代码
nums = [1,2,3]
# 列表是可迭代对象,不是迭代器,不能直接用next()
next(nums)
# 报错:TypeError: 'list' object is not an iterator

正确代码:先调用iter()转为迭代器,再用next()

复制代码
nums = [1,2,3]
nums_iter = iter(nums)
print(next(nums_iter))  # 正常输出1

坑3:自定义迭代器时,__iter__方法没有返回自身

错误代码

复制代码
class BadIterator:
    def __init__(self):
        self.current = 0
    def __iter__(self):
        # 错误:没有返回迭代器对象,返回了None
        print("__iter__被调用了")
    def __next__(self):
        if self.current >= 3:
            raise StopIteration
        self.current += 1
        return self.current

# 报错:TypeError: iter() returned non-iterator of type 'NoneType'
for num in BadIterator():
    print(num)

正确代码:__iter__方法必须返回迭代器自身

复制代码
class GoodIterator:
    def __init__(self):
        self.current = 0
    def __iter__(self):
        # 正确:返回迭代器自身
        return self
    def __next__(self):
        if self.current >= 3:
            raise StopIteration
        self.current += 1
        return self.current

for num in GoodIterator():
    print(num)

坑4:自定义迭代器时,没有抛出StopIteration异常,导致无限循环

错误代码

复制代码
class InfiniteLoopIterator:
    def __init__(self):
        self.current = 0
    def __iter__(self):
        return self
    def __next__(self):
        # 错误:没有终止条件,不抛StopIteration异常
        self.current += 1
        return self.current

# 无限循环,永远不会停止
for num in InfiniteLoopIterator():
    print(num)

正确代码:必须设置终止条件,无元素时抛出StopIteration

复制代码
class NormalIterator:
    def __init__(self):
        self.current = 0
    def __iter__(self):
        return self
    def __next__(self):
        # 正确:设置终止条件,抛异常结束迭代
        if self.current >= 3:
            raise StopIteration
        self.current += 1
        return self.current

for num in NormalIterator():
    print(num)

坑5:对迭代器使用len()函数获取长度

错误代码

复制代码
nums_iter = iter([1,2,3])
# 迭代器不支持len(),因为元素是惰性生成的,无法提前知道长度
print(len(nums_iter))
# 报错:TypeError: object of type 'list_iterator' has no len()

正确代码:如果需要获取长度,先转为列表,或提前在可迭代对象中定义长度

复制代码
nums_iter = iter([1,2,3])
# 转为列表后获取长度(会耗尽迭代器)
nums_list = list(nums_iter)
print(len(nums_list))

九、实战案例(完整可运行代码)

9.1 实战1:大文件逐行读取(迭代器内存优势)

处理GB级别的大文件时,用readlines()会一次性把整个文件加载到内存,导致内存溢出;用文件迭代器逐行读取,内存占用始终极低。

复制代码
def read_large_file(file_path):
    """
    用迭代器逐行读取大文件,内存占用极低
    :param file_path: 文件路径
    """
    print("========== 大文件逐行读取实战 ==========")
    line_count = 0
    # 文件句柄本身就是迭代器,逐行迭代,不会一次性加载整个文件
    with open(file_path, "r", encoding="utf-8") as f:
        # for循环自动调用next(),逐行读取
        for line in f:
            # 处理每一行数据
            line = line.strip()
            if line:  # 跳过空行
                line_count += 1
                # 这里可以添加你的业务处理逻辑
                if line_count <= 5:  # 只打印前5行
                    print(f"   第{line_count}行:{line}")
    print(f"\n文件总行数:{line_count}")
    print(f"内存占用:仅当前行的内容,不会加载整个文件")

# 测试:先生成一个测试大文件,再读取
if __name__ == "__main__":
    # 生成测试文件
    with open("large_test.log", "w", encoding="utf-8") as f:
        for i in range(10000):
            f.write(f"这是第{i}行日志,记录了系统运行状态\n")
    # 读取大文件
    read_large_file("large_test.log")

9.2 实战2:自定义分页数据迭代器

在爬虫、接口请求等场景中,数据是分页返回的,用迭代器实现惰性加载,无需一次性请求所有分页数据,用的时候才请求下一页。

复制代码
import requests

class PageDataIterator:
    """分页数据迭代器,惰性请求分页接口"""
    def __init__(self, base_url, max_page=10):
        """
        初始化
        :param base_url: 接口基础地址
        :param max_page: 最大请求页数
        """
        self.base_url = base_url
        self.max_page = max_page
        self.current_page = 1  # 当前页码

    def __iter__(self):
        return self

    def __next__(self):
        # 终止条件:超过最大页码
        if self.current_page > self.max_page:
            raise StopIteration
        # 模拟请求接口,获取当前页数据(实战中替换为真实接口请求)
        print(f"正在请求第{self.current_page}页数据...")
        # 真实场景:response = requests.get(self.base_url, params={"page": self.current_page})
        # data = response.json()
        # 模拟返回数据
        data = {
            "page": self.current_page,
            "data": [f"数据{i}" for i in range((self.current_page-1)*10, self.current_page*10)]
        }
        # 页码+1,为下一次请求做准备
        self.current_page += 1
        # 返回当前页数据
        return data

# 测试分页迭代器
if __name__ == "__main__":
    print("========== 分页数据迭代器实战 ==========")
    # 创建分页迭代器,最多请求3页
    page_iter = PageDataIterator("https://api.example.com/data", max_page=3)
    
    # 遍历迭代器,自动逐页请求数据
    for page_data in page_iter:
        print(f"第{page_data['page']}页数据:{page_data['data'][:3]}...(共10条)")

9.3 实战3:数据处理流水线(迭代器组合使用)

用多个迭代器组合成数据处理流水线,惰性计算,每一步只处理当前元素,内存占用极低,适合大数据处理。

复制代码
import itertools

def data_process_pipeline():
    """迭代器组合的数据处理流水线"""
    print("========== 数据处理流水线实战 ==========")
    
    # 原始数据:1-10的数字
    nums = range(1, 11)
    print(f"原始数据:{list(nums)}")
    
    # 构建处理流水线(全是迭代器,不执行实际计算,调用next()时才执行)
    # 步骤1:过滤出偶数
    step1 = filter(lambda x: x % 2 == 0, nums)
    # 步骤2:每个数乘以2
    step2 = map(lambda x: x * 2, step1)
    # 步骤3:累加计算
    step3 = itertools.accumulate(step2)
    # 步骤4:过滤出大于20的数
    step4 = itertools.dropwhile(lambda x: x < 20, step3)
    
    # 执行流水线,获取最终结果
    print(f"处理结果:{list(step4)}")
    print("处理流程:过滤偶数 → 乘以2 → 累加 → 过滤大于20的数")

# 运行测试
data_process_pipeline()

十、迭代器核心知识点速查表

|------------|----------------------------------------------------------|
| 知识点 | 核心说明 |
| 可迭代对象 | 实现了__iter__()方法的对象,能被for循环遍历 |
| 迭代器 | 同时实现了__iter__()__next__()方法的对象,符合迭代器协议 |
| iter()函数 | 将可迭代对象转为迭代器 |
| next()函数 | 获取迭代器的下一个元素,无元素时抛StopIteration异常 |
| for循环底层 | 先调用iter()获取迭代器,循环调用next(),捕获StopIteration结束 |
| 核心特性 | 惰性计算、一次性遍历、内存高效、支持无限序列 |
| 自定义迭代器 | 实现__iter__()(返回self)和__next__()(返回元素,无元素抛异常) |
| 内置迭代器函数 | map、filter、zip、enumerate,返回值均为迭代器 |
| itertools库 | Python内置的高效迭代器工具库,提供大量迭代器创建函数 |
| 生成器 | 特殊的迭代器,用yield关键字或生成器表达式创建,代码更简洁 |
| 常见坑 | 迭代器耗尽无法重复遍历、可迭代对象不能直接用next()、__iter__不返回self、无终止条件导致无限循环 |

相关推荐
dragen_light1 小时前
5.ROS2-Topics-Publisher-Subscriber
python
jr-create(•̀⌄•́)1 小时前
LeakyRelu链式法则
开发语言·python·深度学习
vx_biyesheji00012 小时前
计算机毕业设计:Python股价预测与可视化系统 Flask框架 数据分析 可视化 机器学习 随机森林 大数据(建议收藏)✅
python·机器学习·信息可视化·数据分析·flask·课程设计
t***5447 小时前
如何配置Orwell Dev-C++使用Clang
开发语言·c++
CoderCodingNo8 小时前
【信奥业余科普】C++ 的奇妙之旅 | 13:为什么 0.1+0.2≠0.3?——解密“爆int”溢出与浮点数精度的底层原理
开发语言·c++
lulu12165440788 小时前
Claude Code项目大了响应慢怎么办?Subagents、Agent Teams、Git Worktree、工作流编排四种方案深度解析
java·人工智能·python·ai编程
Ares-Wang8 小时前
Flask》》 Flask-Bcrypt 哈希加密
后端·python·flask
kongba0079 小时前
项目打包 Python Flask 项目发布与打包专家 提示词V1.0
开发语言·python·flask
froginwe119 小时前
C 语言测验
开发语言