使用理解而不是for循环

时间:2016-08-06 22:21:43

标签: python list-comprehension

以下是我的代码的简化示例。

>>> def action(num):
        print "Number is", num
>>> items = [1, 3, 6]
>>> for i in [j for j in items if j > 4]:
        action(i)
Number is 6

我的问题如下:不好的做法(出于代码清晰度等原因)只需用理解来替换for循环,这仍然会调用{{1}功能?那就是:

action

3 个答案:

答案 0 :(得分:4)

这根本不应该使用生成器或理解。

JQuery

发电机懒洋洋地评价。表达式def action(num): print "Number is", num items = [1, 3, 6] for j in items: if j > 4: action(i) 仅将生成器表达式返回给调用者。除非你明确地用尽它,否则什么都不会发生。列表理解会急切地评估,但是,在这种特殊情况下,你会留下一个没有目的的(action(j) for j in items if j > 2)。只需使用常规循环。

答案 1 :(得分:1)

虽然我个人赞成Tigerhawk's solution,但他和willywonkadailyblah的解决方案(现已删除)之间可能存在中间立场。

willywonkadailyblah的观点之一是:

  

为什么要创建新列表而不是仅使用旧列表?你已经有了过滤掉正确元素的条件,那么为什么要将它们放在内存中并为它们回来呢?

避免此问题的一种方法是使用过滤的延迟评估,即只有在使用for循环进行迭代时才进行过滤,方法是使生成器表达式的过滤部分而不是列表理解:

for i in (j for j in items if j > 4):
    action(i)

<强>输出

Number is 6

老实说,我认为Tigerhawk的解决方案是最好的解决方案。这只是一种可能的选择。

我提出这个的原因是它让我想起了C#中的很多LINQ查询,你在这里定义了一种从一个语句(LINQ表达式)中的序列中提取,过滤和投影元素的惰性方法,然后可以使用与该查询分开的for each循环,以对每个元素执行某些操作。

答案 2 :(得分:1)

这是不好的做法。首先,您的代码片段不会产生所需的输出。你会得到类似的东西:<generator object <genexpr> at 0x03D826F0>

其次,列表理解用于创建序列,而生成器用于创建对象流。通常,它们没有副作用。你的动作函数是副作用的一个主要例子 - 它打印输入并且什么都不返回。相反,生成器应该为它生成的每个项目,接受输入并计算一些输出。例如

doubled_odds = [x*2 for x in range(10) if x % 2 != 0]

通过使用生成器,您正在混淆代码的目的,即改变全局状态(打印某些东西),而不是创建对象流。 然而,仅使用for循环会使代码稍长(基本上只是更多的空格),但是您可以立即看到目的是将函数应用于选择的项目(而不是创建新的流/项目列表)。

for i in items:
    if i < 4:
        action(i)

请记住,生成器仍然是循环结构,并且底层字节码或多或少相同(如果有的话,生成器的效率稍差),就会失去清晰度。生成器和列表推导很好,但对他们来说这不是正确的情况。