我有一个列表,我想通过项目的属性进行筛选。
以下哪个是首选(可读性,性能,其他原因)?
xs = [x for x in xs if x.attribute == value]
xs = filter(lambda x: x.attribute == value, xs)
我有一个列表,我想通过项目的属性进行筛选。
以下哪个是首选(可读性,性能,其他原因)?
xs = [x for x in xs if x.attribute == value]
xs = filter(lambda x: x.attribute == value, xs)
当前回答
奇怪的是,在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
其他回答
过滤器就是这样。它过滤掉列表中的元素。你可以看到定义中提到了同样的内容(在我之前提到的官方文档链接中)。然而,列表理解是在对前一个列表上的内容进行操作后产生一个新的列表。(过滤器和列表推导式都创建新列表,而不执行替换旧列表的操作。这里的新列表类似于具有全新数据类型的列表。比如将整数转换为字符串,等等)
在您的示例中,根据定义,使用过滤器比使用列表理解更好。但是,如果您希望,例如列表元素中的other_attribute,在您的示例中是作为一个新列表检索,那么您可以使用列表推导式。
return [item.other_attribute for item in my_list if item.attribute==value]
这就是我对筛选器和列表理解的记忆。删除列表中的一些东西,并保持其他元素完整,使用过滤器。在元素上使用一些自己的逻辑,并创建一个适合某些目的的稀释列表,使用列表理解。
奇怪的是,不同的人的美相差如此之大。我发现列表理解比filter+lambda清晰得多,但使用您认为更容易的。
有两件事可能会减慢你使用滤镜的速度。
首先是函数调用开销:一旦使用Python函数(无论是由def还是lambda创建的),过滤器很可能会比列表理解慢。几乎可以肯定,这并不重要,在对代码进行计时并发现它是一个瓶颈之前,您不应该过多地考虑性能,但区别是存在的。
可能应用的另一个开销是lambda被强制访问一个有作用域的变量(值)。这比在python2中访问局部变量要慢。X,列表推导式只访问局部变量。如果你使用的是Python 3。X,列表综合在一个单独的函数中运行,因此它也将通过闭包访问值,这种差异将不适用。
另一个可以考虑的选项是使用生成器而不是列表推导式:
def filterbyvalue(seq, value):
for el in seq:
if el.attribute==value: yield el
然后在你的主代码中(这是可读性真正重要的地方),你用一个有意义的函数名替换了列表理解和过滤器。
一个重要的区别是,列表推导式将返回一个列表,而过滤器返回一个过滤器,你不能像操作列表一样操作它(即:在它上调用len,它不能与过滤器的返回一起工作)。
我自己的自学也让我遇到了类似的问题。
也就是说,如果有一种方法可以从过滤器获得结果列表,有点像在。net中执行lst时所做的那样。Where(i => i.something()). tolist(),我很想知道它。
编辑:这是Python 3的情况,而不是Python 2(见评论中的讨论)。
你的问题既简单又有趣。它只是显示了python作为一种编程语言是多么的灵活。人们可以使用任何逻辑,根据自己的才能和理解来编写程序。只要我们得到答案就好。
在您的情况下,这只是一个简单的过滤方法,可以由两者完成,但我更喜欢第一个my_list = [x for x in my_list if x.attribute == value],因为它看起来简单,不需要任何特殊的语法。任何人都可以理解这个命令,并在需要时进行更改。 (虽然第二种方法也很简单,但对于初级程序员来说,它仍然比第一种方法更复杂)
尽管过滤器可能是“更快的方式”,但“Python方式”是不关心这些事情,除非性能绝对关键(在这种情况下,您不会使用Python!)。