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

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

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

当前回答

当我需要在列表理解之后过滤一些东西时,我使用了一小段。只是过滤器、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])]

其他回答

奇怪的是,在Python 3上,我看到过滤器执行得比列表推导更快。

我一直认为列表推导式的性能会更好。 喜欢的东西: [name为brand_names_db中的name,如果name不是None] 生成的字节码稍好一些。

>>> def f1(seq):
...     return list(filter(None, seq))
>>> def f2(seq):
...     return [i for i in seq if i is not None]
>>> disassemble(f1.__code__)
2         0 LOAD_GLOBAL              0 (list)
          2 LOAD_GLOBAL              1 (filter)
          4 LOAD_CONST               0 (None)
          6 LOAD_FAST                0 (seq)
          8 CALL_FUNCTION            2
         10 CALL_FUNCTION            1
         12 RETURN_VALUE
>>> disassemble(f2.__code__)
2           0 LOAD_CONST               1 (<code object <listcomp> at 0x10cfcaa50, file "<stdin>", line 2>)
          2 LOAD_CONST               2 ('f2.<locals>.<listcomp>')
          4 MAKE_FUNCTION            0
          6 LOAD_FAST                0 (seq)
          8 GET_ITER
         10 CALL_FUNCTION            1
         12 RETURN_VALUE

但它们实际上更慢:

   >>> timeit(stmt="f1(range(1000))", setup="from __main__ import f1,f2")
   21.177661532000116
   >>> timeit(stmt="f2(range(1000))", setup="from __main__ import f1,f2")
   42.233950221000214

一般过滤器稍快,如果使用内置函数。

在您的情况下,我希望列表理解稍微快一些

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

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

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

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

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

过滤器就是这样。它过滤掉列表中的元素。你可以看到定义中提到了同样的内容(在我之前提到的官方文档链接中)。然而,列表理解是在对前一个列表上的内容进行操作后产生一个新的列表。(过滤器和列表推导式都创建新列表,而不执行替换旧列表的操作。这里的新列表类似于具有全新数据类型的列表。比如将整数转换为字符串,等等)

在您的示例中,根据定义,使用过滤器比使用列表理解更好。但是,如果您希望,例如列表元素中的other_attribute,在您的示例中是作为一个新列表检索,那么您可以使用列表推导式。

return [item.other_attribute for item in my_list if item.attribute==value]

这就是我对筛选器和列表理解的记忆。删除列表中的一些东西,并保持其他元素完整,使用过滤器。在元素上使用一些自己的逻辑,并创建一个适合某些目的的稀释列表,使用列表理解。