问题:当Python看到这种表达时,它会做什么?
sum(sum(i) for j in arr for i in j)
我的想法:上面的表达方式有效。但正如用Python's docs写的那样:
生成器表达式使用函数作用域
实现
不要冗长:)我有一个具有以下布局的数组(作为示例):
>>> arr = [
[[1,2,3], [4,5,6]],
[[7,8,9],[10,11,12]]
]
首先,我尝试将arr
的所有元素与以下表达式相加:
>>> sum(sum(i) for i in j for j in arr)
NameError: name 'j' is not defined
它引发NameError
,但为什么不UnboundLocalError: local variable 'j' referenced before assignment
如果是使用函数范围实现的,for ... in ...
从左到右或从右到右的评估规则是什么?剩下?什么是这个生成器表达式的等效生成器函数?
修改:
我抓住了这个主意。感谢@vaultah的一些见解。在这种情况下,j
是发送到生成器表达式的参数:
>>> sum(sum(i) for i in j for j in arr) # NameError
这就是为什么我得到这个奇怪的NameError
。
@Eric answer显示了生成器表达式:
>>> sum(sum(i) for j in arr for i in j)
相当于:
>>> def __gen(arr):
for j in arr:
for i in j:
yield sum(i)
>>> sum(__gen(arr))
答案 0 :(得分:2)
当Python看到这种表达时,它会做什么?
container->inputOption
它变得相当于:
sum(sum(i) for j in array for i in j)
请注意,def __gen(it):
# "it" is actually in locals() as ".0"
for j in it:
for i in j:
yield sum(i)
sum(__gen(iter(arr)))
和名称解析都发生在函数范围之外。这仅适用于第一个__iter__
循环
PEP 0289更详细地解释了这一点
答案 1 :(得分:1)
无论是生成器还是列表理解,理解嵌套都是一样的。通过列表理解更容易看到正在发生的事情,这就是我将在下面的示例中使用的内容。
假设:
>>> arr
[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]
您可以使用嵌套列表推导(或生成器)将Ints列表列表压平1级:
>>> [e for sl in arr for e in sl]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
在给定结构的情况下,您可以通过再次嵌套完全展平(仅限示例;有更好的方法来展平深层嵌套列表):
>>> [e2 for sl2 in [e for sl in arr for e in sl] for e2 in sl2]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
由于sum
采用可迭代,因此在您的示例中不需要第二次展平:
>>> [sum(e) for sl in arr for e in sl]
[6, 15, 24, 33] # sum of those is 78...
理解的一般形式是:
[ expression for a_variable in a_DEFINED_sequence optional_predicate ]
通过使用未定义的名称,您可以获得与嵌套理解相同的NameError
:
>>> [c for c in not_defined]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'not_defined' is not defined
因此,您在sum(sum(i) for i in j for j in arr)
上看到的错误是因为j
尚未定义。理解从左到右,从内到外进行评估。 j
作为序列的定义是其尝试使用的权利。
要将列表推导展开为嵌套循环,内部(或左手)部分将成为外部循环:
for sl in arr:
for sl2 in sl:
for e in sl2:
# now you have each int in the LoLoInts...
# you could use yield e for a generator here
您的最后一个问题:为什么TypeError
带有gen = (j for j in arr)
?
那个生成器表达式什么都不做。例如:
>>> [j for j in arr]
[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]
>>> [j for j in arr] == arr
True
所以表达式(j for j in arr)
只返回arr
上的生成器。
并且sum
不知道如何添加或者arr:
>>> sum(arr)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'list'
由于示例中的gen
返回相同的数据结构,这是您的错误。
修复它:
>>> gen=(e for sl in arr for e in sl)
>>> sum(sum(li) for li in gen)
78