pin_drop当前位置:知识文库 ❯ 图文

Python迭代协议详解 - __iter__与__next__完全指南

一、什么是迭代协议

迭代协议(Iteration Protocol)是Python中最核心的协议之一。它定义了一套规则,让对象能够被for循环、list()tuple()等内置函数遍历。

简单来说,迭代协议就是Python对象之间的一种"约定":只要遵守这套约定,你的对象就能像列表、元组一样被遍历。


二、可迭代对象与迭代器

可迭代对象(Iterable)

可迭代对象是指实现了__iter__方法的对象。常见的可迭代对象包括列表、元组、字典、集合和字符串。

可以使用collections.abc.Iterable来判断一个对象是否可迭代:

代码示例

from collections.abc import Iterable

# 常见的可迭代对象
print(isinstance([1, 2, 3], Iterable))      # True
print(isinstance("hello", Iterable))        # True
print(isinstance({"a": 1}, Iterable))       # True
print(isinstance((1, 2), Iterable))         # True
print(isinstance(100, Iterable))            # False - 整数不可迭代

迭代器(Iterator)

迭代器是特殊的可迭代对象,它必须同时实现__iter____next__两个方法。迭代器能够记住遍历的位置,每次调用__next__时返回下一个值。

特性 可迭代对象 迭代器
实现方法 __iter__ __iter__ 和 __next__
可被for循环
可多次遍历 否(一次性)
可用next()
典型例子 list、str、dict 文件对象、enumerate

三、__iter__与__next__方法

__iter__方法

__iter__方法返回一个迭代器对象。对于可迭代对象而言,这个方法会在for循环开始时被自动调用。

代码示例

my_list = [10, 20, 30]

# 调用iter()实际上是调用__iter__()
iterator = iter(my_list)
print(type(iterator))  # <class 'list_iterator'>

__next__方法

__next__方法返回容器中的下一个元素。当没有更多元素时,必须抛出StopIteration异常,这是通知循环结束的信号。

代码示例

my_list = [10, 20, 30]
iterator = iter(my_list)

print(next(iterator))  # 10
print(next(iterator))  # 20
print(next(iterator))  # 30
print(next(iterator))  # 抛出 StopIteration 异常

四、代码示例详解

示例1:手动模拟for循环

代码示例

# for循环的底层实现原理
fruits = ["apple", "banana", "cherry"]

# 获取迭代器
iterator = iter(fruits)

# 手动模拟for循环
while True:
    try:
        item = next(iterator)
        print(f"水果: {item}")
    except StopIteration:
        # 迭代结束,退出循环
        break

# 输出:
# 水果: apple
# 水果: banana
# 水果: cherry

示例2:使用itertools查看迭代过程

代码示例

from itertools import islice

# 创建一个简单的迭代器
numbers = iter(range(1, 11))

# 使用islice获取前5个元素
first_five = list(islice(numbers, 5))
print(f"前5个: {first_five}")  # 前5个: [1, 2, 3, 4, 5]

# 迭代器已经消费了前5个,继续获取剩余的
remaining = list(numbers)
print(f"剩余: {remaining}")    # 剩余: [6, 7, 8, 9, 10]

示例3:多个迭代器的独立性

代码示例

data = [1, 2, 3, 4, 5]

# 从同一个可迭代对象创建两个独立的迭代器
iter1 = iter(data)
iter2 = iter(data)

print(next(iter1))  # 1
print(next(iter2))  # 1(独立的迭代器,从开头开始)
print(next(iter1))  # 2
print(next(iter2))  # 2

五、注意事项与最佳实践

注意1:迭代器是一次性的。一旦遍历完成(抛出StopIteration),再次遍历将不会得到任何元素。需要重新调用iter()创建新的迭代器。

注意2:迭代器对象本身就是可迭代对象。迭代器的__iter__方法返回自身,这就是为什么迭代器可以被for循环遍历的原因。

注意3:不要直接调用__next__和__iter__方法,应该使用内置函数next()和iter(),它们会提供更友好的错误处理。

小贴士

使用collections.abc模块中的IterableIterator可以准确判断对象类型。Python 3.3+推荐使用collections.abc而非旧版的collections


六、练习题

练习1

编写代码验证以下对象哪些是可迭代对象,哪些是迭代器:列表、字典、文件对象、字符串、range对象。使用isinstance()配合Iterable和Iterator进行判断。

练习2

编写一个函数,接受任意可迭代对象作为参数,使用手动迭代的方式(while循环 + next + try/except)统计元素个数,但不能使用len()函数。

常见问题

可迭代对象和迭代器有什么区别?

可迭代对象实现了__iter__方法,可以被for循环遍历,但每次遍历时会创建一个新的迭代器。迭代器同时实现了__iter__和__next__方法,可以记住遍历位置,但只能遍历一次。所有迭代器都是可迭代对象,但反过来不成立。

为什么迭代器只能遍历一次?

因为迭代器会记录当前的遍历位置。当遍历完成后,位置已经到达末尾,再次调用__next__会抛出StopIteration。如果需要重新遍历,必须调用iter()创建新的迭代器。

for循环的底层工作原理是什么?

for循环首先调用可迭代对象的__iter__方法获取迭代器,然后不断调用迭代器的__next__方法获取元素,当遇到StopIteration异常时自动退出循环。这就是for循环的完整生命周期。

range()返回的是迭代器吗?

不是。range()返回的是一个可迭代的range对象,它不是迭代器。你可以多次遍历同一个range对象,每次遍历都会创建新的迭代器。可以用iter(range(5))来获取其迭代器。

标签: 迭代协议 __iter__ __next__ 可迭代对象 迭代器 StopIteration

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python异常链详解 - raise from与异常上下文追踪 下一篇: Python自定义迭代器 - 实现迭代器类与斐波那契数列

poll相关推荐