我有一个列表,我想通过项目的属性进行筛选。
以下哪个是首选(可读性,性能,其他原因)?
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)
当前回答
我花了一些时间来熟悉高阶函数过滤器和映射。所以我习惯了他们,我实际上喜欢过滤器,因为它是明确的,它通过保持任何真实的过滤,我觉得很酷,我知道一些函数编程术语。
然后我读了这篇文章(Fluent Python Book):
映射和筛选函数仍然是内置的 在Python 3中,但是自从引入了列表推导式和generator ex‐ 压力没有那么重要。listcomp或genexp完成map和的工作 过滤器组合,但更可读。
现在我想,如果您可以使用已经广泛传播的习语(如列表推导)来实现它,那么为什么还要使用过滤器/映射的概念呢?此外,映射和过滤器是一种函数。在这种情况下,我更喜欢使用匿名函数lambdas。
最后,为了进行测试,我对两种方法(map和listComp)都进行了计时,我没有看到任何相关的速度差异,可以证明这是合理的。
from timeit import Timer
timeMap = Timer(lambda: list(map(lambda x: x*x, range(10**7))))
print(timeMap.timeit(number=100))
timeListComp = Timer(lambda:[(lambda x: x*x) for x in range(10**7)])
print(timeListComp.timeit(number=100))
#Map: 166.95695265199174
#List Comprehension 177.97208347299602
其他回答
你的问题既简单又有趣。它只是显示了python作为一种编程语言是多么的灵活。人们可以使用任何逻辑,根据自己的才能和理解来编写程序。只要我们得到答案就好。
在您的情况下,这只是一个简单的过滤方法,可以由两者完成,但我更喜欢第一个my_list = [x for x in my_list if x.attribute == value],因为它看起来简单,不需要任何特殊的语法。任何人都可以理解这个命令,并在需要时进行更改。 (虽然第二种方法也很简单,但对于初级程序员来说,它仍然比第一种方法更复杂)
当我需要在列表理解之后过滤一些东西时,我使用了一小段。只是过滤器、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])]
由于任何速度差异都必然是微乎其微的,因此使用过滤器还是列表推导式都取决于个人喜好。一般来说,我倾向于使用推导式(这似乎与这里的大多数其他答案一致),但有一种情况下,我更喜欢过滤器。
一个非常常见的用例是根据谓词P(X)提取某个可迭代对象X的值:
[x for x in X if P(x)]
但有时你想先对值应用一些函数:
[f(x) for x in X if P(f(x))]
作为一个具体的例子,请考虑
primes_cubed = [x*x*x for x in range(1000) if prime(x)]
我认为这看起来比使用滤镜要好一点。但是现在想想
prime_cubes = [x*x*x for x in range(1000) if prime(x*x*x)]
在本例中,我们希望根据后计算值进行过滤。除了计算立方体两次的问题(想象一个更昂贵的计算),还有编写表达式两次的问题,这违反了DRY美学。在这种情况下,我会使用
prime_cubes = filter(prime, [x*x*x for x in range(1000)])
一个重要的区别是,列表推导式将返回一个列表,而过滤器返回一个过滤器,你不能像操作列表一样操作它(即:在它上调用len,它不能与过滤器的返回一起工作)。
我自己的自学也让我遇到了类似的问题。
也就是说,如果有一种方法可以从过滤器获得结果列表,有点像在。net中执行lst时所做的那样。Where(i => i.something()). tolist(),我很想知道它。
编辑:这是Python 3的情况,而不是Python 2(见评论中的讨论)。
这在Python中有点像宗教问题。尽管Guido考虑从Python 3中删除map、filter和reduce,但还是有足够的反对意见,最终只有reduce从内置迁移到functools.reduce。
就我个人而言,我发现列表推导式更容易阅读。从表达式[i for i in list if i.attribute == value]中发生的事情更加明确,因为所有的行为都在表面上,而不是在过滤器函数内部。
我不会太担心这两种方法之间的性能差异,因为它是微不足道的。我只会优化它,如果它被证明是你的应用程序的瓶颈,这是不太可能的。
此外,由于BDFL希望从语言中删除过滤器,那么肯定会自动使列表理解更python化;-)