Python 3中filter()函数多次调用后结果为空的原因咨询
关于Python 3中filter()对象的一次性迭代问题
嘿,这个问题问到点子上了——核心原因是Python 3里的filter()返回的是一个迭代器(iterator),而不是像列表那样可重复遍历的容器。迭代器的本质是“按需生成/消耗元素”,遍历一次之后就会被耗尽,里面再也没有元素可以取出来了。咱们一步步拆解你的问题:
为什么第一次操作后myList2为空?
让我们还原你的第一组代码执行流程:
myList = [1, 2, 3, 4, 5] myList = filter(lambda i: i <= 3, myList) # myList现在是一个filter迭代器,对应元素是1、2、3(但还没实际生成) myList2 = filter(lambda i: i == 1, myList) # myList2是基于myList这个迭代器的新迭代器 print(list(myList)) # 这里会遍历myList迭代器的所有元素,把1、2、3取出来转成列表输出 print(list(myList2)) # 这时候myList已经被遍历耗尽了,myList2去遍历它的时候没有元素可取,所以输出[]
关键在于:当你调用list(myList)时,已经把myList这个迭代器里的所有元素都“取完”了。迭代器不像列表那样把所有元素存在内存里,它是边遍历边生成元素,遍历结束后就空了,后续再对它进行遍历(比如myList2的filter操作)就拿不到任何元素了。
为什么转成list后原filter对象变空?
再看你的第二组代码:
myList = [1, 2, 3, 4, 5] myList = filter(lambda i: i <= 3, myList) # 还是一个filter迭代器 myList2 = filter(lambda i: i == 1, list(myList)) # 这里的list(myList)会先遍历myList迭代器,把元素转成[1,2,3] print(list(myList)) # 此时myList已经被list()遍历耗尽,所以输出[] print(list(myList2)) # myList2是基于新生成的列表[1,2,3]的filter,能正常筛选出1,所以输出[1]
这里的list(myList)操作同样是一次性耗尽了原filter迭代器的元素——迭代器的遍历是不可逆的,一旦被遍历完,就再也拿不到元素了。而myList2是基于新生成的列表(容器,可重复遍历)做的filter,所以能正常工作。
怎么避免这个问题?
既然你已经会用列表推导式,其实可以类比理解:列表推导式生成的是一个实实在在的容器,你可以反复使用;而filter()返回的迭代器是“一次性用品”。如果需要多次使用filter()的结果,**提前把它转成列表(或元组)**就好:
myList = [1, 2, 3, 4, 5] myList = list(filter(lambda i: i <= 3, myList)) # 直接转成列表,可重复遍历 myList2 = filter(lambda i: i == 1, myList) print(list(myList)) # 输出[1,2,3] print(list(myList2)) # 输出[1]
当然,用你熟悉的列表推导式实现同样的效果也完全没问题,而且可读性可能更好:
myList = [i for i in [1,2,3,4,5] if i <=3] myList2 = [i for i in myList if i ==1]
内容的提问来源于stack exchange,提问作者Alexandr Zarubkin
相关产品推荐
相关产品推荐

