我有一个列表,我想通过项目的属性进行筛选。
以下哪个是首选(可读性,性能,其他原因)?
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)
当前回答
我觉得第二种方法更容易读懂。它确切地告诉你目的是什么:过滤列表。 注意:不要使用list作为变量名
其他回答
奇怪的是,不同的人的美相差如此之大。我发现列表理解比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
然后在你的主代码中(这是可读性真正重要的地方),你用一个有意义的函数名替换了列表理解和过滤器。
除了公认的答案之外,还有一种极端情况,即您应该使用过滤器而不是列表推导式。如果列表是不可哈希的,则不能使用列表推导式直接处理它。一个真实的例子是使用pyodbc从数据库读取结果。游标的fetchAll()结果是一个不可哈希的列表。在这种情况下,要直接对返回的结果进行操作,应该使用filter:
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)
如果你在这里使用列表理解,你会得到错误:
TypeError:不可哈希类型:list
尽管过滤器可能是“更快的方式”,但“Python方式”是不关心这些事情,除非性能绝对关键(在这种情况下,您不会使用Python!)。
当我需要在列表理解之后过滤一些东西时,我使用了一小段。只是过滤器、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])]
就性能而言,这要视情况而定。
filter不返回一个列表而是一个迭代器,如果你需要列表“立即”过滤和列表转换,它比非常大的列表(>1M)的列表理解要慢40%左右。到100K的元素几乎没有区别,从600K开始就开始有区别了。
如果不转换为列表,筛选实际上是即时的。
更多信息请访问:https://blog.finxter.com/python-lists-filter-vs-list-comprehension-which-is-faster/