列表推导式 vs lambda + filter
列表推导式 vs lambda + filter
我有一个列表,我想按照项目的属性进行过滤。
哪种方式更受欢迎(易读性、性能、其他原因)?
xs = [x for x in xs if x.attribute == value]
xs = filter(lambda x: x.attribute == value, xs)
这是Python中一个略带宗教色彩的问题。虽然Guido曾考虑将map
、filter
和reduce
从Python 3中移除,但是由于引起了足够激烈的反弹,最后只有reduce
从内置函数被移动到functools.reduce中。
个人认为列表解析更容易阅读。通过表达式[i for i in list if i.attribute == value]
可以更清楚地表达出所有的行为,而不是在过滤函数内部进行实现。
我不会过分担心这两种方法之间的性能差异,因为它是微不足道的。我真正只会在应用程序中这部分代码成为瓶颈的情况下去优化它,而这是不太可能发生的。
另外,由于BDFL在语言中希望去掉filter
,因此肯定会使列表解析更符合Python的特性;-)
很奇怪人们对于美的认知存在很大差别。我认为列表推导式比filter
+lambda
更明确,但你可以使用你觉得更容易的方法。
有两件事情可能会降低你使用filter
的速度。
第一件事是函数调用的开销:一旦你使用Python函数(不管是通过def
还是lambda
创建的),filter
很可能会比列表推导式慢。这几乎肯定是微不足道的,你不应该太关注性能,直到你计时后发现这是一个问题,但差别确实存在。
另一个可能适用的开销是lambda被强制访问一个作用域变量(value
)。这比访问局部变量慢,在Python 2.x中,列表推导式只访问局部变量。如果你使用的是Python 3.x,列表推导式在一个独立的函数中运行,因此也将通过闭包访问value
,这个差别将不适用。
另一个要考虑的选择是使用生成器而不是列表推导式:
def filterbyvalue(seq, value): for el in seq: if el.attribute==value: yield el
然后在你的主要代码中(这是真正重要的可读性),你用一个有意义的函数名替换了列表推导式和filter
。