Python列表理解语法可以轻松地在理解中过滤值.例如:
result = [x**2 for x in mylist if type(x) is int]
将返回mylist中整数的平方列表.但是,如果测试涉及一些(昂贵的)计算并且您想要对结果进行过滤,该怎么办?一种选择是:
result = [expensive(x) for x in mylist if expensive(x)]
这将导致非"虚假"昂贵(x)值的列表,但是每个x调用两次昂贵的().是否有一种理解语法允许您进行此测试,而每次只调用一次昂贵的一次?
经过一分钟的思考后,我想出了自己的答案.它可以通过嵌套的理解来完成:
result = [y for y in (expensive(x) for x in mylist) if y]
我猜这有用,虽然我发现嵌套的理解只是边缘可读
如果计算已经很好地捆绑到函数中,那么如何使用filter
和map
?
result = filter (None, map (expensive, mylist))
itertools.imap
如果列表非常大,您可以使用.
最明显的(我认为最可读)答案是不使用列表推导或生成器表达式,而是使用真正的生成器:
def gen_expensive(mylist): for item in mylist: result = expensive(item) if result: yield result
它需要更多的水平空间,但更容易看到它一目了然,你最终不会重复自己.
result = [x for x in map(expensive,mylist) if x]
map()将返回传递给expensive()的mylist中每个对象的值列表.然后你可以列出 - 理解它,并丢弃不必要的值.
这有点像嵌套的理解,但应该更快(因为python解释器可以相当容易地优化它).
这正是发电机适合处理的:
result = (expensive(x) for x in mylist) result = (do_something(x) for x in result if some_condition(x)) ... result = [x for x in result if x] # finally, a list
这使得在管道的每个阶段发生的事情都非常清楚.
显式过度隐含
使用发生器到处都是最后一步,所以没有大的中间列表
cf: David Beazley的"系统程序员的生成器技巧"