2015-05-10 227 views
1

我迷惑關於濾鏡功能在Python 3.X 假設下一個代碼的行爲:過濾器過濾列表在Python 3

>>> 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

我剛剛運行代碼它在python2.7上完美工作。你確定它在python 3中不起作用嗎? – RafaelC

回答

1

問題是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)和迭代器evalutated,僅使用的num最後一個值。

一個解決方案可能在每次迭代中都使用list(filter(...)),因爲它已經被提出。

但是,如果你想節省內存,這裏是你如何可以「凍結」編號:

>>> 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的值的引用,並避免在內部範圍內通過名稱引用它。

0

問題是filter返回過濾器對象的實例。對於你的代碼寫的工作,你必須使用過濾器對象在循環創建一個新的列表

for num in range(4): 
    test = list(filter(lambda x: x != num, test)) 
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)) 

通過在3 第三線鑄造listtest,我們可以有效地去除項目,我們不希望:

>>> print(list(test)) 
[4, 5, 6, 7, 8] 
>>>