枚举

时间:2017-03-07 17:26:43

标签: python list loops iterator enumerate

我知道我不应该在循环中修改列表,但出于好奇,我想知道为什么以下两个示例之间的迭代次数不同。

示例1:

x = [1, 2, 3, 4, 5]
for i, s in enumerate(x):
    del x[0]
    print(i, s, x)

示例2:

x = [1,2,3,4,5]
for i, s in enumerate(x):
    x = [1]
    print(i, s, x)

示例1仅运行3次,因为i==3len(x)==2

即使len(x)==1,例2也会运行5次。

所以我的问题是,enumerate是否在循环开始时生成(index, value)对的完整列表并迭代它?或者它们是在循环的每次迭代中生成的?

6 个答案:

答案 0 :(得分:22)

在第一个示例中,您实际上正在修改正在迭代的列表。

另一方面,在第二种情况下,您只是将新对象分配给名称x。但循环迭代的对象不会改变。

有关Python中名称和变量的更详细说明,请查看http://foobarnbaz.com/2012/07/08/understanding-python-variables/

答案 1 :(得分:18)

enumerate()返回迭代器或其他支持迭代的对象。 __next__()返回的迭代器的enumerate()方法返回一个包含计数的元组(从start开始,默认为0)和从迭代 iterable 获得的值。

__next__()返回容器中的下一个项目。如果没有其他项目,请提出StopIteration例外。

  

enumerate()是否在循环开始时生成(索引,值)对的完整列表并迭代它?或者它们是在循环的每次迭代中生成的?

因此,enumerate()返回一个迭代器,并且在每次迭代时,__next__()都会检查是否还有其他项。 enumerate()在循环开始时不会创建完整列表。

正如@Wisperwind提到的那样,在您的第二种情况下,您要为名称x分配新对象。循环遍历的对象在迭代期间不会改变。

答案 2 :(得分:8)

只是澄清了Wasi Ahmad和Wisperwind所说的话。两者都声明“您只是将新对象分配给名称x”。这可能会有点混乱,因为它可能被解释为“你正在创建一个新对象([1])并将其存储到名称x,你会说”嗯,所以为什么不改变?!“要看看发生了什么,打印出对象的id

x = [1, 2, 3, 4, 5]
y = x  # To keep a reference to the original list
print id(x), id(y)
for i, v in enumerate(x):
    x = [1]
    print id(x), id(y)
print id(x), id(y)


# output (somewhat contrived as I don't have a python environment set up)
#    X ID            Y ID
10000000000001 10000000000001
10000000000002 10000000000001
10000000000003 10000000000001
10000000000004 10000000000001
10000000000005 10000000000001
10000000000006 10000000000001
10000000000006 10000000000001

您会注意到id的{​​{1}}每次都在循环中发生变化,当您完成循环后,x将指向最后一次修改循环。当你完成循环时,它会迭代x的原始实例,无论你是否仍然可以引用它。

如您所见,x指向原始y。当您在循环中进行迭代时,即使x正在发生变化,x仍然指向仍在循环的原始y

答案 3 :(得分:1)

确实:您的第一个代码段修改了迭代列表;第二个将变量x指向一个新列表,保留未经修改的enumerate()横向列表。您可以通过访问www.pythontutor.com上的以下链接来查看此操作,该链接允许您单步执行代码并可视化变量的内容:

为了更好地了解正在进行的操作,请转到here,然后跳过以下扩展代码:

x = [1,2,3,4,5]
view = enumerate(x)
for i, s in view:
    x = [1]
    print(i, s, x)

答案 4 :(得分:1)

其他人已经指出,您的第二个示例只会更改x点的值,而不会更改您重复的列表。这是普通作业(x = [1])和slice assignmentx[:] = [1])之间差异的完美示例。后者将列表x修改为就地

x = [1, 2, 3, 4, 5]
for i, s in enumerate(x):
    x[:] = [1]
    print(i, s, x)

将打印

(0, 1, [1])

答案 5 :(得分:0)

x = [1, 2, 3, 4, 5]

列表[1, 2, 3, 4, 5]已标记为x

for i, s in enumerate(x):

enumerate()附加了另一个标记,因此[1, 2, 3, 4, 5]现已标记为xy。 enumerate()将继续使用y标记,而不是x标记。

del x[0]

存储在内存中的列表已修改,因此xy现在都引用[2, 3, 4, 5]

或者,当您使用

x = [1]

在内存中创建了一个新列表[1]x标记现在指向该列表。 y标记仍指向原始列表。

Python变量如何工作:
http://foobarnbaz.com/2012/07/08/understanding-python-variables/