Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 列表理解中的生成器表达式未按预期工作_Python_Python 3.x_List Comprehension_Generator Expression - Fatal编程技术网

Python 列表理解中的生成器表达式未按预期工作

Python 列表理解中的生成器表达式未按预期工作,python,python-3.x,list-comprehension,generator-expression,Python,Python 3.x,List Comprehension,Generator Expression,以下代码生成预期的输出: # using a list comprehension as the first expression to a list comprehension >>> l = [[i*2+x for x in j] for i,j in zip([0,1],[range(4),range(4)])] >>> l[0] [0, 1, 2, 3] >>> l[1] [2, 3, 4, 5] 但是,当我使用生成器表达式时,会得

以下代码生成预期的输出:

# using a list comprehension as the first expression to a list comprehension
>>> l = [[i*2+x for x in j] for i,j in zip([0,1],[range(4),range(4)])]
>>> l[0]
[0, 1, 2, 3]
>>> l[1]
[2, 3, 4, 5]
但是,当我使用生成器表达式时,会得到不同的结果:

# using a generator expression as the first expression
>>> l = [(i*2+x for x in j) for i,j in zip([0,1],[range(4),range(4)])]
>>> list(l[0])
[2, 3, 4, 5]
>>> list(l[1])
[2, 3, 4, 5]
>>> list(l[0])
[]
>>> list(l[1])
[]
>>> l
[<generator object <listcomp>.<genexpr> at 0x7fddfa413ca8>, <generator object <listcomp>.<genexpr> at 0x7fddfa413c50>]
#使用生成器表达式作为第一个表达式
>>>l=[(i*2+x代表j中的x)代表i,j代表zip([0,1],[range(4),range(4)])]
>>>列表(l[0])
[2, 3, 4, 5]
>>>列表(l[1])
[2, 3, 4, 5]
>>>列表(l[0])
[]
>>>列表(l[1])
[]
>>>l
[, ]
我知道生成器表达式只能使用一次,但是我很难推理为什么在这个场景中会两次得到相同的列表,特别是因为生成器对象看起来是唯一的


我错过了什么?这是在Python 3.6.5上测试的。

生成器对象是唯一的,但是它们引用了
i
j
,但是列表理解终止(这实际上创建了一个函数范围,就像列表理解中的生成器表达式一样)。因此,
i
j
具有值
i==1
j==range(4)
。你甚至可以反省一下:

In [1]: l = [(i*2+x for x in j) for i,j in zip([0,1],[range(4),range(4)])]

In [2]: g = l[0]

In [3]: g.gi_frame.f_locals
Out[3]: {'.0': <range_iterator at 0x10e9be960>, 'i': 1}
不过,也许为了清楚起见,我将使用不同的参数名称来更清楚地说明发生了什么:

In [12]: l = [(lambda a, b: (a*2+x for x in b))(i, j) for i,j in zip([0,1],[range(4),range(4)])]

In [13]: list(l[0])
Out[13]: [0, 1, 2, 3]

In [14]: list(l[1])
Out[14]: [2, 3, 4, 5]

因为在执行每个生成器表达式时,
i
被绑定到1。生成器表达式不会捕获创建时生效的绑定-它们使用执行时生效的绑定

>>> j = 100000
>>> e = (j for i in range(3))
>>> j = -6
>>> list(e)
[-6, -6, -6]

这是有道理的;我假设它自动实现了某种类型的闭包。我喜欢通过lambda@MikeLui它确实创建了一个闭包。本质上,生成器表达式使用函数作用域。这与列表中的
lambda:i
(创建闭包)始终返回
2
的原因相同。
In [12]: l = [(lambda a, b: (a*2+x for x in b))(i, j) for i,j in zip([0,1],[range(4),range(4)])]

In [13]: list(l[0])
Out[13]: [0, 1, 2, 3]

In [14]: list(l[1])
Out[14]: [2, 3, 4, 5]
>>> j = 100000
>>> e = (j for i in range(3))
>>> j = -6
>>> list(e)
[-6, -6, -6]