Ago*_*gos 793 python lambda functional-programming list filter
我碰巧发现自己有一个基本的过滤需求:我有一个列表,我必须通过项目的属性过滤它.
我的代码看起来像这样:
my_list = [x for x in my_list if x.attribute == value]
Run Code Online (Sandbox Code Playgroud)
但后来我想,这样写它会不会更好?
my_list = filter(lambda x: x.attribute == value, my_list)
Run Code Online (Sandbox Code Playgroud)
它更具可读性,如果需要性能,可以取出lambda来获得一些东西.
问题是:使用第二种方式有什么警告吗?任何性能差异?我是否完全错过了Pythonic Way™并且应该以另一种方式(例如使用itemgetter而不是lambda)来完成它?
Dun*_*can 547
很奇怪,不同的人有多少美丽.我发现列表理解比filter+ 更清晰lambda,但是使用你发现的更容易.但是,请停止提供已用于内置函数的变量名称,这令人困惑.[ 该问题最初用作filter变量名称,但已根据此答案进行了更新.]
有两件事可能会减慢你的使用速度def.
第一个是函数调用开销:只要你使用Python函数(无论是由lambdaor 创建value),过滤器可能会比列表理解慢.几乎可以肯定这并不重要,在你对代码进行计时并发现它成为瓶颈之前,你不应该考虑性能,但差异就在那里.
可能适用的另一个开销是lambda被强制访问范围变量(value).这比访问局部变量要慢,而在Python 2.x中,列表推导只访问局部变量.如果您使用的是Python 3.x,则列表推导在一个单独的函数中运行,因此它也将filter通过闭包进行访问,这种差异将不适用.
另一个要考虑的选择是使用生成器而不是列表推导:
def filterbyvalue(seq, value):
for el in seq:
if el.attribute==value: yield el
Run Code Online (Sandbox Code Playgroud)
然后在你的主代码中(这是可读性真正重要的地方)你已经用一个有希望的有意义的函数名替换了列表理解和过滤器.
Ten*_*she 219
这在Python中是一个有些宗教问题.即使Guido考虑删除map,filter而且reduce从Python 3开始,还有足够的强烈反对,最终只是reduce从内置函数转移到functools.reduce.
我个人认为列表推导更容易阅读.从表达式发生的事情更明确,[i for i in list if i.attribute == value]因为所有行为都在表面上而不是在过滤器函数内部.
我不会太担心两种方法之间的性能差异,因为它是边缘的.如果它被证明是你的应用程序的瓶颈,我真的只会优化它,这是不太可能的.
此外,因为BDFL希望filter从语言中消失,然后肯定会自动使列表理解更加Pythonic ;-)
I. *_*edy 67
由于任何速度差异必然微乎其微,因此无论是使用过滤器还是列表理解,都归结为品味问题.一般来说,我倾向于使用理解(这似乎与大多数其他答案一致),但有一个案例我更喜欢filter.
一个非常频繁的用例是将一些可迭代X的值拉出到谓词P(x):
[x for x in X if P(x)]
Run Code Online (Sandbox Code Playgroud)
但有时您想先将一些函数应用于值:
[f(x) for x in X if P(f(x))]
Run Code Online (Sandbox Code Playgroud)
作为具体的例子,考虑一下
primes_cubed = [x*x*x for x in range(1000) if prime(x)]
Run Code Online (Sandbox Code Playgroud)
我认为这看起来比使用稍好filter.但现在考虑一下
prime_cubes = [x*x*x for x in range(1000) if prime(x*x*x)]
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们想要filter反对后计算值.除了计算立方体两次的问题(想象一个更昂贵的计算),存在两次写表达式的问题,违反了DRY美学.在这种情况下,我会倾向于使用
prime_cubes = filter(prime, [x*x*x for x in range(1000)])
Run Code Online (Sandbox Code Playgroud)
Uma*_*ang 28
尽管filter可能是"更快的方式",但"Pythonic方式"并不关心这些事情,除非性能绝对是关键的(在这种情况下你不会使用Python!).
Jim*_*m50 18
我以为我只是在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)
Run Code Online (Sandbox Code Playgroud)
列表b和c具有相同的值,并且在filter()等效的同时完成[x,如果z则为x的x].但是,在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))
Run Code Online (Sandbox Code Playgroud)
问题是list()接受一个可迭代的参数,并从该参数创建一个新的列表.结果是在python 3中以这种方式使用过滤器所需的时间是[x for y in z]方法的两倍,因为您必须迭代filter()以及原始列表的输出.
Ade*_*ack 12
一个重要的区别是列表理解将返回一段list时间过滤器返回a filter,你不能像a一样操作list(即:调用len它,它不适用于返回filter).
我自己的自学带来了一些类似的问题.
话虽如此,如果有一种方法可以得到lista 的结果filter,有点像你在.NET中做的那样lst.Where(i => i.something()).ToList(),我很想知道它.
编辑:这是Python 3的情况,而不是2(参见评论中的讨论).
过滤就是这样.它过滤掉列表的元素.您可以看到定义提及相同(在我之前提到的官方文档链接中).然而,列表理解是在行动之后产生新列表的东西在对前一列表中的某些事物进行操作事情.(过滤器和列表理解都创建新列表而不执行操作来代替旧列表.这里的新列表就像列表一样比方说,一个全新的数据类型.像将整数转换为字符串等)
在您的示例中,根据定义,最好使用过滤器而不是列表推导.但是,如果您愿意,例如,从列表元素中说other_attribute,您的示例中的other_attribute将作为新列表检索,那么您可以使用list comprehension.
return [item.other_attribute for item in my_list if item.attribute==value]
Run Code Online (Sandbox Code Playgroud)
这就是我实际记住过滤器和列表理解的方法.删除列表中的一些内容并保持其他元素不变,使用过滤器.在元素上使用一些逻辑并创建适合某些目的的淡化列表,使用列表理解.
这是我在列表理解后需要过滤某些内容时使用的短片.只是过滤器,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])]
Run Code Online (Sandbox Code Playgroud)
我花了一些时间来熟悉higher order functions filter和map。所以我习惯了它们,我真的很喜欢它们filter,因为它很明确地通过保留真实的内容来过滤,而且我知道一些术语,这让我感觉很酷functional programming。
然后我读了这段话(Fluent Python Book):
\n\n\n\n\n映射和过滤函数仍然是 Python 3 中的内置函数,但由于引入了列表推导式和生成器 ex\xe2\x80\x90\n 表达式,它们不再那么重要。listcomp 或 genexp 完成映射和过滤器的组合工作,但更具可读性。
\n
现在我想, 如果你可以用列表推导式等已经广泛传播的习语来实现它,为什么还要费心filter/的概念呢?map此外maps, 和filters是函数的一种。在这种情况下,我更喜欢使用Anonymous functionslambda。
最后,只是为了对其进行测试,我对两种方法 (map和listComp) 进行了计时,并且我没有看到任何相关的速度差异来证明对此进行争论是合理的。
from timeit import Timer\n\ntimeMap = Timer(lambda: list(map(lambda x: x*x, range(10**7))))\nprint(timeMap.timeit(number=100))\n\ntimeListComp = Timer(lambda:[(lambda x: x*x) for x in range(10**7)])\nprint(timeListComp.timeit(number=100))\n\n#Map: 166.95695265199174\n#List Comprehension 177.97208347299602\nRun Code Online (Sandbox Code Playgroud)\n
小智 5
除了可接受的答案外,还有一个极端的情况,您应该使用过滤器而不是列表推导。如果列表不可散列,则无法直接使用列表推导处理它。一个真实的例子是,如果您用来pyodbc从数据库中读取结果。在fetchAll()从结果cursor是unhashable列表。在这种情况下,要直接处理返回的结果,应使用过滤器:
cursor.execute("SELECT * FROM TABLE1;")
data_from_db = cursor.fetchall()
processed_data = filter(lambda s: 'abc' in s.field1 or s.StartTime >= start_date_time, data_from_db)
Run Code Online (Sandbox Code Playgroud)
如果您在此处使用列表理解,则会出现错误:
TypeError:无法散列的类型:“列表”