嵌套列表理解的奇怪行为

时间:2017-10-08 12:32:05

标签: python list-comprehension

我有以下代码:

[e for e in [sl] for sl in [1,[2,3],4,5]]

我认为(在输出方面)相当于:

[sl for sl in [1,[2,3],4,5]]

然而,后者产生:[1,[2,3],4,5]前者返回:[5, 5, 5, 5]

我认为它必须与嵌套for-statements的评估方式有关。

我在Weird behavior: Lambda inside list comprehension发现了一个类似的案例,但由于它使用了匿名函数,因此这种行为背后的原因应该是不同的。

显然,我有一些遗失的东西,我不知道。

感谢您的任何澄清

更新

帕特里克指出,两个for的顺序是错误的,除非之前定义sl,否则不应该运行。我在这里骗了自己,因为我在解释器中运行了示例,[sl for sl in [1,[2,3],4,5]]首先执行,sl设置为globals()

中列表的最后一个值


现在了解如何评估

会很棒
[e for e in [sl] for sl in [1,[2,3],4,5]]

以便在输出中生成[5, 5, 5, 5]

2 个答案:

答案 0 :(得分:2)

代码中的其他地方是否定义了sl?也许是5?如上所述,您的第一个示例不应该运行,并且不会在Python 3.6中运行。写它的正确方法是

[e for sl in [1,[2,3],4,5] for e in [sl]]

请注意,此处sl在使用之前已定义。

编辑:

Python从左到右读取列表推导。当它到达for e in [sl]时,它会根据已知的内容评估表达式[sl],而不会读取该行的其余部分。列表理解就像是

[e for e in [5] for sl in [1,[2,3],4,5]]

由于sl中有四个[[1,[2,3],4,5]],因此您会在结果列表中获得5四次。

在编写列表推导时,将它们从最小到最大编写

是很自然的
e for e in x for x in y for y in z #wrong

但实际上你应该从右到左编写它们,以便解释器识别你在嵌套理解中使用的标识符

e for y in z for x in y for e in x

这与常规for循环没有区别:

for e in x:
    for x in y:
        for y in z:
            print(e)

显然是错误的,列表推导也没有什么不同。

答案 1 :(得分:0)

代码可以运行的唯一方法是在其他位置定义sl。如果是(如5),那么代码:

sl = 5

[e for e in [sl] for sl in [1,[2,3],4,5]]

产生输出:

[5,5,5,5]

<强>为什么吗

发生这种情况的原因是从for-loopsevaluate的{​​{1}} left。所以第一件事就是将right分配给e - 正如您可能的那样:

5

会给[i for i in [9]]

现在我们知道,无论最右边的9如何,for-loop的值始终都是e的值,所以在我们的案例中sl。现在,为什么输出5?好吧它令人困惑,因为变量[5,5,5,5]正在重复使用。但是,这不会影响sl的{​​{1}},因为它会将left评估为list-comprehension。因此left始终具有righte)的值,无论右侧是[sl]。右手5只是作为一个反击。由于其中包含sl个元素(loop41[2,3]),因此左侧部分运行4次。但5始终为4,因此每次调用e时都会5 - 生成结果e

为了证明右侧只是一个计数器,以下所有会产生5的相同结果:

[5,5,5,5]