[英]Why doesn't Python's filter(predicate, set) return a set?
為什么要設計Python的filter
,使得如果運行filter(my_predicate, some_set)
,我得到的list
對象返回的不是set
對象?
在實際情況下,您不希望將結果set
...嗎?
您可以進行設定的理解。
{my_predicate(x) for x in some_set} # mapping
{x for x in some_set if my_predicate(x)} # filtering
如
In [1]: s = set([1,2,3])
In [2]: {x%2 for x in s}
Out[2]: {0, 1}
Python 2中的許多“功能”函數都以將list
作為輸出類型進行了標准化。 這只是很久以前的API選擇。 在itertools
許多相同的“功能”函數都標准化了提供生成器的功能,您可以從該生成器中填充所需的任何數據結構。 並且在Python 3中,它們在提供迭代器上是標准化的。
但也請注意,Python中的“過濾”與其他語言中的“過濾”不同,例如Haskell。 它不被認為是數據結構的上下文中一個轉變,你沒有選擇,使它們函子的一個實例,“賦予”您的數據“過濾性”結構(或任何其它類似的想法在其他語言中存在) 。
結果,這是Python中的一個常見用例,它說:“這是一個集合,但是我只想返回所有小於5的值。在此之后,我不在乎它們的“設置”我將對它們進行其他工作,所以請給我一個____。” 無需為保存值最初存在的上下文而瘋狂。
在動態打字文化中,這是非常合理的。 但是在靜態類型文化中,在轉換期間保留類型可能很重要,這會令人感到沮喪。 從Python的特定角度來看,這實際上只是一種啟發。
如果確實只是在set
或tuple
的非常狹窄的上下文中,那么我可能只寫了一個輔助函數:
def type_preserving_filter(predicate, data):
return type(data)(filter(predicate, data))
如
>>> type_preserving_filter(lambda x: x > 3, set([1,2,3,4,5,6,7,7]))
{4, 5, 6, 7}
>>> type_preserving_filter(lambda x: x > 3, list([1,2,3,4,5,6,7,7]))
[4, 5, 6, 7, 7]
>>> type_preserving_filter(lambda x: x > 3, tuple([1,2,3,4,5,6,7,7]))
(4, 5, 6, 7, 7)
在Python 2.10和Python 3.4中均可使用。 在Python 2中,這有點浪費。 使用Python 3中的迭代器進行構造會更好。
這不限於filter()
。 但是API已在Python 3中進行了更改,其中filter()
現在返回迭代器而不是列表。 引用python文檔:
視圖和迭代器而不是列表
一些著名的API不再返回列表:
...
map()
和filter()
返回迭代器。 如果您確實需要列表,則快速修復方法是例如list(map(...))
,但是更好的解決方法通常是使用列表理解(尤其是當原始代碼使用lambda時),或者重寫代碼以使其不根本不需要列表。 為函數的副作用調用map()
尤其棘手; 正確的轉換是使用常規的for循環(因為創建列表將很浪費)。
由Python的作者撰寫的這篇文章詳細介紹了在Python 3中刪除filter()
原因(但是,盡管推理仍然很重要,但這並未如您在上面看到的那樣發生。)
Python 3000中
reduce()
的命運...
我認為刪除
filter()
和map()
毫無爭議;filter(P, S)
幾乎總是更清楚地寫為[x for x in S if P(x)]
,這具有巨大的優勢,即最常用的用法是比較謂詞,例如x==42
,並定義一個lambda只是需要讀者付出更多的努力(加上lambda比列表理解要慢)。 對於map(F, S)
甚至更是如此map(F, S)
它成為[F(x) for x in S]
map(F, S)
[F(x) for x in S]
。 當然,在許多情況下,您可以改為使用生成器表達式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.