为何Python3循环内过滤后列表为空?Lambda筛选质数异常排查
问题根源:Python 3中
filter()返回迭代器而非列表,迭代器只能遍历一次 这是Python 2和Python 3的核心差异导致的问题!咱们一步步拆解:
你的代码里的关键问题点
先看补全后的代码片段:
def test1(): num = 50 primes = range(2, num) for i in range(2, 8): print(list(primes)) # 这里会遍历primes的所有元素 primes = filter(lambda x: x % i != 0, primes)
在Python 3中:
- 初始的
range(2, num)返回的是可迭代对象(不是列表,但可以多次遍历),但第一次循环后,你把primes赋值成了filter()的返回值——而filter()在Python3里返回的是迭代器。 - 迭代器的核心特性是:只能被遍历一次。当你调用
list(primes)时,会一次性取出迭代器里的所有元素,之后这个迭代器就被彻底耗尽,再访问它就没有任何元素了。
具体循环过程拆解
- 第一次循环(i=2):
- 初始
primes是range(2,50),调用list(primes)会输出[2,3,4,...,49](range可多次遍历,这里没问题)。 - 然后
primes = filter(...)把它变成了一个装着所有奇数的迭代器。
- 初始
- 第二次循环(i=3):
- 你调用
list(primes),遍历这个迭代器取出所有奇数,此时这个迭代器已经空了。 - 接着
primes = filter(lambda x: x%3 !=0, primes)——这里的primes已经是耗尽的迭代器,新的filter自然没有元素可以处理,所以后续primes就变成了空的迭代器,之后的循环打印都是空列表。
- 你调用
解决方法
把filter()的结果转换成列表,让primes始终是可多次遍历的列表,而不是一次性的迭代器:
def test1(): num = 50 primes = list(range(2, num)) # 先转成列表 for i in range(2, 8): print(primes) # 直接打印列表,不需要再转 primes = list(filter(lambda x: x % i != 0, primes)) # 每次filter后转成列表
或者,如果你想保留迭代器的内存优化特性,可以在打印前先复制一份迭代器的内容,避免耗尽原迭代器:
def test1(): num = 50 primes = range(2, num) for i in range(2, 8): primes_list = list(primes) print(primes_list) primes = filter(lambda x: x % i != 0, primes_list) # 基于列表创建新的filter对象
补充:Python 2 vs Python 3的差异
你参考的Python 2示例里,filter()返回的是列表,列表可以被多次遍历,所以原来的代码能正常运行。但Python 3为了优化内存,把filter()、map()这类函数的返回值改成了迭代器,这就是代码失效的核心原因。
内容的提问来源于stack exchange,提问作者cypher
相关产品推荐
相关产品推荐

