我有一个列表,我想通过项目的属性进行筛选。

以下哪个是首选(可读性,性能,其他原因)?

xs = [x for x in xs if x.attribute == value]
xs = filter(lambda x: x.attribute == value, xs)

当前回答

这在Python中有点像宗教问题。尽管Guido考虑从Python 3中删除map、filter和reduce,但还是有足够的反对意见,最终只有reduce从内置迁移到functools.reduce。

就我个人而言,我发现列表推导式更容易阅读。从表达式[i for i in list if i.attribute == value]中发生的事情更加明确,因为所有的行为都在表面上,而不是在过滤器函数内部。

我不会太担心这两种方法之间的性能差异,因为它是微不足道的。我只会优化它,如果它被证明是你的应用程序的瓶颈,这是不太可能的。

此外,由于BDFL希望从语言中删除过滤器,那么肯定会自动使列表理解更python化;-)

其他回答

当我需要在列表理解之后过滤一些东西时,我使用了一小段。只是过滤器、lambda和列表的组合(或者称为猫的忠诚度和狗的清洁度)。

在这种情况下,我正在读取一个文件,剥离空行,注释掉行,以及在一行的注释之后的任何内容:

# Throw out blank lines and comments
with open('file.txt', 'r') as lines:        
    # From the inside out:
    #    [s.partition('#')[0].strip() for s in lines]... Throws out comments
    #   filter(lambda x: x!= '', [s.part... Filters out blank lines
    #  y for y in filter... Converts filter object to list
    file_contents = [y for y in filter(lambda x: x != '', [s.partition('#')[0].strip() for s in lines])]

我觉得第二种方法更容易读懂。它确切地告诉你目的是什么:过滤列表。 注意:不要使用list作为变量名

尽管过滤器可能是“更快的方式”,但“Python方式”是不关心这些事情,除非性能绝对关键(在这种情况下,您不会使用Python!)。

我想我只是在python 3中添加,filter()实际上是一个迭代器对象,所以你必须将你的filter方法调用传递给list(),以构建过滤后的列表。所以在python 2中:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = filter(lambda num: num % 2 == 0, lst_a)

列表b和c具有相同的值,并且在filter()等效的时间内完成[x for x in y if z]。然而,在3中,相同的代码将使列表c包含一个筛选器对象,而不是一个筛选过的列表。要在3中产生相同的值:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = list(filter(lambda num: num %2 == 0, lst_a))

问题是list()接受一个可迭代对象作为参数,并从该参数创建一个新列表。结果是,在python 3中以这种方式使用filter所花费的时间是[x for x in y if z]方法的两倍,因为你必须遍历filter()的输出以及原始列表。

一个重要的区别是,列表推导式将返回一个列表,而过滤器返回一个过滤器,你不能像操作列表一样操作它(即:在它上调用len,它不能与过滤器的返回一起工作)。

我自己的自学也让我遇到了类似的问题。

也就是说,如果有一种方法可以从过滤器获得结果列表,有点像在。net中执行lst时所做的那样。Where(i => i.something()). tolist(),我很想知道它。

编辑:这是Python 3的情况,而不是Python 2(见评论中的讨论)。