执行生成器表达式的最pythonic方法是什么?

时间:2010-07-09 04:17:21

标签: python lazy-evaluation generator

Python的越来越多的功能变成了“懒惰的可执行文件”,就像生成器一样 表达式和其他类型的迭代器。 然而,有时候,我发现自己想要推出一个“for”循环,只是为了执行一些动作。

实际执行循环的最诡计是什么?

例如:

a = open("numbers.txt", "w")
(a.write ("%d " % i) for i in xrange(100))
a.close()

不是代码,但你明白我的意思。如果我使用列表生成器,相反,我有副作用创建一个填充“无”的N长度列表。

目前我所做的是在调用“any”或“all”时使用表达式作为参数。但是我想找到一种方法,它不依赖于循环中执行的表达式的结果 - “any”和“all”都可以根据所评估的表达式停止。

要清楚,这些是我已经知道的方法,每个都有它的缺点:

[a.write ("%d " % i) for i in xrange(100))]

any((a.write ("%d " % i) for i in xrange(100)))

for item in (a.write ("%d " % i) for i in xrange(100)): pass

4 个答案:

答案 0 :(得分:10)

有一种明显的方法可以做到,这就是你应该这样做的方式。没有理由这样做聪明。

a = open("numbers.txt", "w")
for i in xrange(100):
    a.write("%d " % i)
d.close()

延迟执行为您带来了一个重要的好处:它允许您将序列传递给另一段代码而无需将整个内容保存在内存中。它用于创建有效的序列作为数据类型。

在这种情况下,您不希望延迟执行。你想要执行。你可以......执行。使用for循环。

答案 1 :(得分:7)

如果我想做这个具体的例子,我会写

for i in xrange(100): a.write('%d ' % i)

如果我经常需要使用迭代器来实现其效果,我会定义

def for_effect(iterable):
    for _ in iterable:
        pass

答案 2 :(得分:5)

有许多accumulators会影响他们给出的整个迭代,例如minmax - 但即使他们也不会完全忽略结果例如,如果某些结果是复数,则会在此过程中产生(minmax将引发异常)。我不认为有一个内置的累加器可以完全按照你想要的 - 你必须编写(并添加到你的微型实用功能的个人藏匿处)一个微小的实用功能,如

def consume(iterable):
    for item in iterable: pass

我猜,主要的原因是Python有一个for语句,当它像手套一样适合时你应该使用它(例如,对于你想要的情况consume为; - 。)

BTW,a.write返回None,这是假的,所以any实际上会消耗它(而a.writelines会做得更好!)。但我意识到你只是以此为例; - )。

答案 3 :(得分:0)

现在是2019年- 这是2010年以来不断出现的一个问题。 Python的其中一个邮件列表中的一个最新帖子在该主题上发送了70多封电子邮件,他们再次拒绝为该语言添加consume调用。

在该线程上,实际上显示了该模式下最有效的模式,而且还远远不够明显,因此我将其发布为答案:

import deque

consume = deque(maxlen=0).extend 

然后使用consume可调用来处理生成器表达式。

事实证明,cPython中的deque本机代码实际上是针对maxlen=0情况进行优化的,只会消耗可迭代的内容。
我在问题中提到的anyall调用应该同样有效,但是人们必须担心表达式的真实性才能消耗可迭代对象。


我看到这仍然可能是有争议的,毕竟,显式的两行for循环可以解决这个问题-我记得这个问题,因为我只是在创建一些线程,然后开始然后再联接然后返回的提交(没有consume可调用,即4行,大部分为样板,并且没有受益于在本机代码中循环访问可迭代对象: https://github.com/jsbueno/extracontext/blob/a5d24be882f9aa18eb19effe3c2cf20c42135ed8/tests/test_thread.py#L27