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__与__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模块中的Iterable和Iterator可以准确判断对象类型。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))来获取其迭代器。
本文涉及AI创作
内容由AI创作,请仔细甄别