Python列表的变异:for循环与range(len)的区别

3
为什么下面的代码不会改变传入的列表内容?
def modify(listarg):
    for x in listarg:
        x=x*2

然而这确实会改变它:

def modify(listarg):
    for x in range(len(listarg)):
        listarg[x]=listarg[x]*2
4个回答

1
第一个只给出了迭代变量(x),本质上 for...in 使用内置的 iter 函数。在第二种情况下,您实际上将值绑定到列表。
for x in listarg:
  x=x*2

上面的代码可以理解为:
i = iter(listarg)
x = i.next() # fetch first value
# this value then you double
# which won't effect the element

如需更多详细信息,您可以参考此文章


1
def modify(listarg):
    for x in listarg:
        x=x*2

这里的x只是一个变量,与您正在迭代的x无关。这就像写成:
def modify(listarg):
    for x in listarg:
        y=x*2

在你的第二段代码中,你试图修改列表本身。

如果x只是一个变量,与我正在迭代的x无关,那么为什么如果我打印x,我会得到我正在迭代的x? - Solaxun
因为当你这样做时,你只是打印 x,而不是尝试对其进行赋值。当你尝试对其进行赋值时,Python会自动区分你正在迭代的 x 和你正在赋值的 x - Maroun
我一定误解了for循环究竟迭代的是什么...看起来它不是对列表对象的引用,而是一个副本。 - Solaxun

0

这是因为Python中变量的命名方式(即内存工作方式)。

在第一种情况下,您创建了一个名为x的变量。随着时间的推移,您反复将列表中的值分配给它。在将列表中的值分配给它后,您将其分配为该值的两倍。此时,您仍在谈论x - 您已经从列表中读取了值并将其分配给了x,稍后将x的值的两倍分配给x。因此,让我们看一下这段代码:

def modify(listarg):
    for x in listarg:  # read a value from the list, and assign it as the value of the variable called x
        x=x*2  # x is now 2x

需要记住的关键是,内存中有一个存储名称的空间和一个存储值的空间(假设listarg = [1,2]):

步骤 名称一侧 值一侧 代码 1 x 1 for x in listarg 2. x 2 x = x*2 3. x 2 for x in listarg 4. x 4 x = x*2

所以你看,只有x的值被改变了,而listarg里面的值并没有改变。

在第二个例子中,您直接访问listarg的部分,并更改它们的值:

步骤 名称一侧 值一侧 代码 1. listarg [1,2]
x 0 for x in range(len(listarg)) 2. x 0 listarg [2,2] listarg[x] = listarg[x]*2

我将在这里停止追踪执行,以阐明我的观点:
您正在访问listarg的第0个“隔间”(或索引)并修改其分配的值。 listarg [x]持有的值正在更改,而不是某些其他变量(例如x)的值。

希望这可以帮到您。


0

第一种方法只是将名为x的变量重新绑定到一个对象,其值是当前列表元素值的两倍。它并不对列表做任何操作。

第二种方法通过直接赋值给其元素来修改列表。

这里还有另一种修改列表的方法:

def modify(listarg):
  listarg[:] = [el * 2 for el in listarg]

在这里,[:]是很重要的;如果没有它,我们将创建一个新列表而不是替换现有列表的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接