为什么Python的filter
被设计成如果运行filter(my_predicate, some_set)
,我会返回一个list
对象而不是一个set
对象?
有没有不希望结果为aset
的实际情况。。。?
最佳答案
你可以做一套理解。
{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
上下文中,那么我可以编写一个helper函数: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)
在Python2.10和Python3.4中都有效。在Python2中,这感觉有点浪费;从Python3中的迭代器构造更好。