在今天上课的时候,讲到filter和map函数的时候,我发现了一个神奇的东西,在以前刷算法的时候也一直用这两个函数,但是并没有注意到这一点——那就是他们的一次遍历性。
filter 返回的迭代器只能遍历一次,遍历后就会 “耗尽”,下面是实例:
# 定义过滤条件:筛选偶数
def is_even(n):
return n % 2 == 0
filter_obj = filter(is_even, [1, 2, 3, 4, 5])
# 第一次遍历:有结果
print(list(filter_obj)) # 输出: [2, 4]
# 第二次遍历:迭代器已空,无结果
print(list(filter_obj)) # 输出: []
# 定义映射函数:将数字乘以10
def multiply_by_10(n):
return n * 10
# 创建map迭代器:对列表中的每个元素执行乘10操作
map_obj = map(multiply_by_10, [1, 2, 3, 4, 5])
# 第一次遍历:迭代器有数据,正常输出转换后的结果
print("第一次遍历map迭代器:", list(map_obj)) # 输出: [10, 20, 30, 40, 50]
# 第二次遍历:迭代器已被耗尽,返回空列表
print("第二次遍历map迭代器:", list(map_obj)) # 输出: []
再讲清楚原因之前,我们需要了解什么是惰性迭代器,以及惰性迭代器的底层原理,也是为什么这两个函数有一次遍历性的主要原因了。
惰性迭代器(Lazy Iterator) 是 Python 中一种 “懒加载” 的可迭代对象。
迭代器内部维护着一个“指针”(也叫 “游标”),记录当前遍历到的位置:
Python 中所有迭代器都遵守「迭代器协议」,核心是两个方法:
模拟一下:
# 定义map迭代器
def multiply_by_10(n):
return n * 10
map_obj = map(multiply_by_10, [1,2,3])
# 手动调用next(),模拟遍历过程
print(next(map_obj)) # 指针指向1 → 计算1*10 → 返回10(指针移到2)
print(next(map_obj)) # 指针指向2 → 计算2*10 → 返回20(指针移到3)
print(next(map_obj)) # 指针指向3 → 计算3*10 → 返回30(指针移到末尾)
print(next(map_obj)) # 指针已到末尾 → 抛出StopIteration异常
运行结果:
10
20
30
Traceback (most recent call last):
File "", line 1, in
StopIteration
除了 map/filter,Python 中这些常见对象也是惰性迭代器:
其实很简单,就是把他们转化为可复用的对象就行了,比如说list、tuple等。