从for循环中的列表访问生成器对象时出现意外行为

时间:2015-09-06 07:08:47

标签: python generator

我有以下代码:

l = [(i for j in xrange(2)) for i in xrange(3)]

print list(l[0])

for i in l:
    print list(i)

以下输出:

[2, 2]

[]

[<generator object <genexpr> at 0x022B97B0>, <generator object <genexpr> at 0x022B97B0>]

[<generator object <genexpr> at 0x022B9D00>, <generator object <genexpr> at 0x022B9D00>]

前两行是预期的结果,但最后两个结果看起来适合我。 我想索引l [0]访问之间没有区别,或者通过迭代器访问循环中list的每个元素。你能帮我吗?

3 个答案:

答案 0 :(得分:1)

此问题是由变量名称冲突引起的。 list comprehension使用的变量共享全局命名空间,而不是在python 2.x中使用孤立的命名空间。因此,将变量名称从i更改为不同的名称会为您提供正确的结果。

l = [(i for j in xrange(2)) for i in xrange(3)]

print list(l[0])

# Change variable name to `value`
for value in l:
    print list(value)

这将打印:

[2, 2]
[]
[2, 2]
[2, 2]

为了进一步证明这一点,你可以这样做:

l = [(i for j in xrange(2)) for i in xrange(3)]

print list(l[0])

i = 'another value'

for value in l:
    print list(value)

这会给你:

[2, 2]
[]
['another value', 'another value']
['another value', 'another value']

答案 1 :(得分:0)

问题是你在列表理解中使用了变量ii会与你期望的完全不同。

print i
>> 2

因此,将其更改为item将产生正确的结果。

for item in enumerate(l):
  list(item)

>> [2, 2]
>> [2, 2]
>> [2, 2]

答案 2 :(得分:0)

列表i中的变量l不是列表列表,而是对生成器对象的引用(每次迭代不同)。

>>> l = [(i for j in xrange(2)) for i in xrange(3)]
>>> for i in l:
...     print i
... 
<generator object <genexpr> at 0xb71ed194>
<generator object <genexpr> at 0xb71ed1bc>
<generator object <genexpr> at 0xb71ed1e4>

PEP 0289定义了Generator expressions。它似乎与list comprehension非常相似。直接从PEP 0289引用:

  

“列表推导的经验表明它们在整个Python中具有广泛的实用性。但是,许多用例不需要在内存中创建完整的列表。相反,它们只需要迭代一个元素。时间“。

另见this。在您的情况下,请尝试以下操作:

l = [(i for j in xrange(2)) for i in xrange(3)]
k = [[i for j in xrange(2)] for i in xrange(3)]

print list(l[0])

for i in l:
    print list(i)
for i in k:
    print list(i)

在上面的代码中,l是生成器对象列表,而k是列表列表。

现在,逐一考虑它们。首先检查列表l

>>> l = [(i for j in xrange(2)) for i in xrange(3)]
>>> for i in l:
...     print list(i)
... 
[<generator object <genexpr> at 0xb71c70cc>, <generator object <genexpr> at 0xb71c70cc>]
[<generator object <genexpr> at 0xb71c70a4>, <generator object <genexpr> at 0xb71c70a4>]
[<generator object <genexpr> at 0xb71c71bc>, <generator object <genexpr> at 0xb71c71bc>]
>>> for i in l:
...     print list(i)
... 
[]
[]
[]


您只能迭代生成器对象一次。但是,在其他情况下,我们可以根据需要使用多次。

>>> k = [[i for j in xrange(2)] for i in xrange(3)]
>>> for i in k:
...     print list(i)
... 
[0, 0]
[1, 1]
[2, 2]
>>> for i in k:
...     print list(i)
... 
[0, 0]
[1, 1]
[2, 2]

但是,如果您需要一个元组列表,那么您可以使用它:

>>> l = [tuple(i for j in xrange(2)) for i in xrange(3)]
>>> l
[(0, 0), (1, 1), (2, 2)]
>>> for i in l:
...     print i
... 
(0, 0)
(1, 1)
(2, 2)
>>> for i in l:
...     print i
... 
(0, 0)
(1, 1)
(2, 2)