为什么+运算符不会在.append()的情况下更改列表?

时间:2012-05-25 03:33:51

标签: python list append concatenation

我正在通过Udacity工作,Dave Evans介绍了一个关于列表属性的练习

list1 = [1,2,3,4]
list2 = [1,2,3,4]

list1=list1+[6]
print(list1)
list2.append(6)
print(list2)

list1 = [1,2,3,4]
list2 = [1,2,3,4]

def proc(mylist):
    mylist = mylist + [6]

def proc2(mylist):
    mylist.append(6)

# Can you explain the results given by the four print statements below? Remove
# the hashes # and run the code to check.

print (list1)
proc(list1)
print (list1)

print (list2)
proc2(list2)
print (list2)

输出

[1, 2, 3, 4, 6]
[1, 2, 3, 4, 6]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4, 6]

所以在一个函数中,向集合中添加6并没有显示,但是当它不在函数中时它会显示吗?

6 个答案:

答案 0 :(得分:15)

  

所以在一个函数中,向集合中添加6并没有显示,但是当它不在函数中时它会显示吗?

不,这不是发生的事情。

当您执行mylist = mylist + [6]时,您实际上是在创建一个全新的列表并将其放在本地mylist变量中。执行该函数后,此mylist变量将消失,新创建的列表也将消失。

OTOH执行mylist.append(6)时不创建新列表。您将获得mylist变量中的列表,并将新元素添加到同一列表中。结果是列表(由list2指向)也将自行更改。 mylist变量将再次消失,但在这种情况下,您更改了原始列表。

让我们看看更直观的解释是否可以帮助您:)

致电proc()

后会发生什么

当您编写list1 = [1, 2, 3, 4, 5]时,您正在创建一个新的列表对象(位于等号的右侧)并创建一个新变量list1,它将指向此对象。

Creating new list instance and global variable

然后,当您致电proc()时,您创建了另一个新变量mylist,并且由于您将list1作为参数传递,mylist将指向同一个对象:

Calling method creates local variable

但是,操作mylist + [6] 创建一个全新的列表对象,其内容是mylist指向的对象的内容加上以下列表对象的内容 - 是,[6]。由于您将此新对象归因于mylist,因此我们的方案稍有变化,mylist不再指向list1指向的同一对象:

mylist points to new list object

我没有说的是mylist是一个局部变量:它会在proc()函数结束后消失。因此,当proc()执行结束时,mylist消失了:

mylist is gone

由于没有其他变量指向mylist + [6]生成的对象,它也会消失(因为垃圾收集器*会收集它):

GC collects the list

请注意,最后,list1指向的对象不会更改。

致电proc2()

后会发生什么

致电proc2()时,一切都会发生变化。首先,它是一样的:你创建一个列表......

Creating new list instance and global variable

...并将其作为参数传递给函数,该函数将生成局部变量:

Calling method creates local variable

但是,不是使用生成新列表的+并置运算符,而是将append()方法应用于现有列表。 append()方法不会创建新对象;相反,它改变现有的:

Appending a value to a list

在函数结束后,局部变量将消失,但是它和list1指向的原始对象将会被更改:

It is still altered

由于list1仍指向它,原始列表不会被销毁。

编辑:如果你想看看发生在之前发生的所有这些事情,请转到this radically amazing simulator

enter image description here

*如果您不知道什么是垃圾收集器......那么,您将在了解自己的问题后立即发现。

答案 1 :(得分:3)

python中的变量总是可以被认为是引用。当您使用参数调用函数时,您将传递对实际数据的引用。

当您使用赋值运算符(=)时,您将指定该名称以引用一个全新的对象。因此,mylist = mylist + [6]创建一个包含mylist的旧内容的新列表,以及6,并指定变量mylist以引用新列表。 list1仍指向旧列表,因此没有任何更改。

另一方面,当你使用.append时,实际上是将一个元素附加到变量引用的列表中 - 它没有为变量赋予任何新内容。所以你的第二个函数修改了list2引用的列表。

答案 2 :(得分:2)

通常,在函数proc的第一种情况下,如果声明了

,则只能通过赋值更改全局列表
global mylist

首先,并没有将mylist作为参数传递。但是,在这种情况下,您将收到mylist全局和本地的错误消息: name 'mylist' is local and globalproc中发生的事情是在分配发生时创建本地列表。由于局部变量在函数结束时消失,因此随后打印出来时,对本地列表的任何更改的影响都不会传播到程序的其余部分。

但是在第二个函数proc2中,您通过附加而不是分配来修改列表,因此不需要global关键字,并且对列表的更改显示别处。

答案 3 :(得分:0)

这种形式或其他形式是一个非常常见的问题。我解释了Python参数传递给自己a couple days ago。基本上,其中一个创建一个新列表,另一个修改现有列表。在后一种情况下,引用列表的所有变量都“看到”变化,因为它仍然是同一个对象。

答案 4 :(得分:0)

在第三行,你做了这个

list1=list1+[6]

所以,当你在上面一行之后做了下面的事情时,

print (list1)

你在start和proc过程中创建了打印的list1,它添加了list1 + [6],它在函数proc中创建了一个新列表。如果要追加[6],则不会创建新列表,而是将列表项追加到现有列表中。

但是,请记住。在第7行中,您再次创建了列表

list1 = [1,2,3,4]

现在你想通过显式调用来打印list1,这将打印出你再次重新初始化而不是前一个的list1。

答案 5 :(得分:0)

除了已经给出的全面答案之外,还值得注意的是,如果你想要相同的语法:

mylist = mylist + [6]

...但仍希望列表“就地”更新,您可以这样做:

mylist += [6]

虽然看起来它与第一个版本的功能相同,但实际上与:

相同
mylist.extend([6])

(注意extend获取可迭代的内容并逐个添加,而append获取给定的任何内容并将其作为单个项添加。请参阅append vs. extend完整的解释。)