繁体   English   中英

Python枚举的奇怪行为

[英]Python strange behavior with 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)对的完整列表并迭代它? 或者它们是在循环的每次迭代中生成的?

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

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

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

enumerate()返回一个迭代器或一些支持迭代的其他对象。 enumerate()返回的迭代器的__next __()方法返回一个包含count的元组(从start开始,默认为0)和迭代迭代得到的值。

__next __()返回容器中的下一个项目。 如果没有其他项,请提高StopIteration异常。

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

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

正如@Wisperwind所提到的那样,在你的第二种情况下,你要为名称x指定一个新对象。 循环迭代的对象在迭代期间不会改变。

只是澄清了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

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

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

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

为了更好地了解发生了什么,请转到此处以跳过以下扩展代码:

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

其他人已经指出,你的第二个例子只改变了x指向的值,而不是你要迭代的列表。 这是普通分配( x = [1] )和切片分配x[:] = [1] )之间差异的完美示例。 后者将列表x点修改为就地

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

将打印

(0, 1, [1])
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/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM