我对Python 3.x中过滤器函数的行为感到困惑 假设下一个代码:
>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> for num in range(4):
test = filter( lambda x: x != num, test)
>>> print(list(test))
# [1, 2, 4, 5, 6, 7, 8]
我认为测试变量将包含连续过滤范围(4)中存在的值(num)的结果,但最终列表根本没有被过滤!。
有人可以向我解释这种行为吗?如果可能的话,如何获得预期的结果 #[4,5,6,7,8]
注意:我的原始代码并不像这个简单,但这只是为了说明我发现错误的地方。
答案 0 :(得分:2)
问题是filter
返回一个迭代器,迭代器没有“冻结”num
的值,如下面的代码所示:
>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> for num in range(4):
... test = filter(lambda x: print(x, '!=', num) or x != num, test)
...
>>> list(test)
1 != 3
1 != 3
1 != 3
1 != 3
2 != 3
2 != 3
2 != 3
2 != 3
3 != 3
4 != 3
[...]
[1, 2, 4, 5, 6, 7, 8]
如您所见,当list(test)
和迭代器被评估时,仅使用num
的最后一个值。
一个解决方案可能是在每次迭代中使用list(filter(...))
,因为它已经被提出。
但是如果你想节省内存,这就是你如何“冻结”num:
>>> import functools
>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> not_equal = lambda x, y: x != y
>>> for num in range(4):
... test = filter(functools.partial(not_equal, num), test)
...
>>> list(test)
[4, 5, 6, 7, 8]
(当然,这只是一个例子。尽量让你的代码更具可读性。)
通常,您需要做的是保持对num
的值的引用,并避免在内部范围中按名称引用它。
答案 1 :(得分:0)
问题是filter
返回过滤器对象的实例。对于您编写的代码,您必须使用过滤器对象在循环中创建新列表
for num in range(4):
test = list( filter( lambda x: x != num, test) )
答案 2 :(得分:0)
filter
对象仍然包含test
中的每个对象。因此,请尝试以下方法:
test = [1, 2, 3, 4, 5, 6, 7, 8]
for num in range(4):
test = filter( lambda x: x != num, list(test))
print(list(test))
通过将list
投放到3 rd 行中的test
,我们可以有效地删除我们不想要的项目:
>>> print(list(test))
[4, 5, 6, 7, 8]
>>>