为什么Python的过滤器(谓词,集合)没有返回集合?

时间:2015-08-18 21:41:21

标签: python list filter set python-2.x

为什么Python的filter设计为如果你运行filter(my_predicate, some_set),我会返回一个list对象返回而不是set个对象?
是否存在 希望结果为set ......的实际情况?

2 个答案:

答案 0 :(得分:5)

你可以做一套理解。

{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。它不被认为是在数据结构的上下文中的转换,并且您不选择通过使它们成为Functor(或其他任何其他)的实例来“赋予”您的数据结构“过滤性”其他语言也有类似的想法。)

因此,Python中的一个常见用例是:“这是一个集合,但我只想要回到所有小于5的值。我不关心他们的'set-ness'之后那一点因为我只是要对它们做一些其他工作,所以就给我一个____。“不需要为保留最初生存的值的上下文而疯狂。

在动态打字文化中,这是非常合理的。但是在静态打字文化中,在转换期间保留类型可能很重要,这会有点令人沮丧。从Python的特定角度来看,它实际上只是一种启发式。

如果它真的只是在settuple的非常狭窄的上下文中,那么我可能会写一个辅助函数:

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中的迭代器构造更好。

答案 1 :(得分:1)

这不仅限于filter()。但是在Python 3中已经改变了API,其中filter()现在返回迭代器而不是列表。引用python文档:

  

Views And Iterators Instead Of Lists

     

一些众所周知的API不再返回列表:

     

...

     
      
  • map()和   filter()   返回迭代器。如果你真的需要一个列表,那么快速解决方案就是   list(map(...)),但更好的解决方法通常是使用列表   理解(特别是当原始代码使用lambda时),或   重写代码,使其根本不需要列表。尤其   棘手的是map()为函数的副作用调用;该   正确的转换是使用常规for循环(因为创建一个   列表只是浪费)。
  •   

Python的作者撰写的这篇文章详细说明了在Python 3中放弃filter()的原因(但是这并没有发生,因为你可以看到上面的内容,尽管推理仍然很重要。)

  

The fate of reduce() in Python 3000

     

...

     

我认为放弃filter()map()是毫无争议的;   filter(P, S)几乎总是更清楚地写成[x for x in S if P(x)],这具有最常见用法的巨大优势   涉及比较的谓词,例如x==42,并定义一个   lambda对于读者来说只需要更多的努力(另外   lambda比列表理解慢。更是如此   map(F, S)成为[F(x) for x in S]。当然,在很多   例如,你可以使用生成器表达式。