生成器表达式评估,在...中有多个... for ...部分 [英] Generator expression evaluation with several ... for ... in ... parts
问题描述
问题:当Python看到这种表达时,它在幕后做什么?
Question: What does Python do under the hood when it sees this kind of expression?
sum(sum(i) for j in arr for i in j)
我的想法:上面的表达式有效.但是它是用 生成器表达式是使用函数作用域实现的
generator expressions are implemented using a function scope 不必太冗长:)我有一个具有以下布局的数组(以为例): Not to be verbose :) I have an array with the following layout (as an example): 首先,我尝试使用以下表达式对 At first, I try to sum all elements of 它引发 It raises 编辑: 我明白了.感谢@vaultah的一些见识.在这种情况下, I catch the idea. Thanks @vaultah for some insight. In this case 这就是为什么我得到这个奇怪的 that's why I get this weird @Eric答案显示生成器表达式: 等效于:
>>> arr = [
[[1,2,3], [4,5,6]],
[[7,8,9],[10,11,12]]
]
arr
的所有元素求和:arr
with the following expression:>>> sum(sum(i) for i in j for j in arr)
NameError: name 'j' is not defined
NameError
,但是为什么不 UnboundLocalError:赋值之前引用的本地变量'j'
(如果使用函数作用域实现), ...这个生成器表达式的等效生成器函数是什么?
NameError
, but why not UnboundLocalError: local variable 'j' referenced before assignment
if it is implemented using a function scope, what is evaluation rules for for ... in ...
from left-to-right or from right-to-left? And what is an equivalent generator function for this generator expression? j
是发送到生成器表达式的参数:j
is the argument that is send to generator expression:>>> sum(sum(i) for i in j for j in arr) # NameError
NameError
的原因.NameError
. >>> 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))
推荐答案
无论是生成器还是列表推导,推导嵌套都是相同的.很容易看到列表理解发生了什么,这就是我将在下面的示例中使用的内容.
Whether it is a generator or a list comprehension, the comprehension nesting is the same. It is easier to see what is going on with a list comprehension and that is what I will use in the examples below.
给出:
>>> arr
[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]
您可以使用嵌套列表推导(或生成器)将整数列表的列表展平1级:
You can flatten the List of Lists of Ints by 1 level using a nested list comprehension (or generator):
>>> [e for sl in arr for e in sl]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
在给定该结构的情况下,您可以通过再次嵌套来完全展平(仅作为示例;有更好的方法来展平深度嵌套的列表):
You can flatten completely, given that structure, by nesting again (example only; there are better ways to flatten a deeply nested list):
>>> [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
需要迭代,因此在您的示例中无需进行第二次展平:
Since sum
takes an iterable, the second flattening is not necessary in your example:
>>> [sum(e) for sl in arr for e in sl]
[6, 15, 24, 33] # sum of those is 78...
理解的一般形式是:
The general form of a comprehension is:
[ expression for a_variable in a_DEFINED_sequence optional_predicate ]
通过使用未定义的名称,您可以获得在嵌套理解中看到的相同的 NameError
:
You can get the same NameError
you are seeing on your nested comprehension by using a non defined name:
>>> [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)表示i在arr的j中的i的sum(i))
上看到的错误是因为尚未定义 j
.理解是从左到右,从内到外的.尝试将 j
定义为序列的权利.
So the error you see on sum(sum(i) for i in j for j in arr)
is because j
has not been defined yet. Comprehensions are evaluated left to right, inner to outer. The definition of j
as a sequence is to the right of its attempted use.
要将列表理解展开为嵌套循环,内部(或左手)部分将变为外部循环:
To unroll the list comprehension into nested loops, the inner (or left hand) section becomes the outer loop:
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代表arr中的j)
?
该生成器表达式不执行任何操作.示例:
That generator expression does nothing. Example:
>>> [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代表arr中的j)
只是通过 arr
返回一个生成器.
So the expression (j for j in arr)
just returns a generator over arr
.
sum
也不知道如何添加或添加arr:
And sum
does not know how to add that or arr either:
>>> sum(arr)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'list'
由于示例中的 gen
返回相同的数据结构,因此出现了错误.
Since gen
in your example is returning the same data structure, that is your error.
要修复它:
>>> gen=(e for sl in arr for e in sl)
>>> sum(sum(li) for li in gen)
78
这篇关于生成器表达式评估,在...中有多个... for ...部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!