为什么+运算符不会在.append()的情况下更改列表?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么+运算符不会在.append()的情况下更改列表?相关的知识,希望对你有一定的参考价值。
我正在通过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并没有显示,但是当它不在函数中时它会显示?
不,这不是发生的事情。
当你执行mylist = mylist + [6]
时,你正在有效地创建一个全新的列表并将其放在本地mylist
变量中。执行该函数后,此mylist
变量将消失,新创建的列表也将消失。
当您执行mylist.append(6)
时,OTOH不会创建新列表。您将获得mylist
变量中的列表,并将新元素添加到同一列表中。结果是列表(由list2
指出)也会自行改变。 mylist
变量将再次消失,但在这种情况下,您更改了原始列表。
让我们看看更直观的解释是否可以帮助你:)
What happens when you call proc()
当您编写list1 = [1, 2, 3, 4, 5]
时,您正在创建一个新的列表对象(在等号的右侧)并创建一个新变量list1
,它将指向此对象。
然后,当你调用proc()
时,你创建另一个新变量mylist
,并且因为你传递list1
作为参数,mylist
将指向同一个对象:
然而,操作mylist + [6]
创建了一个全新的列表对象,其内容是mylist
指向的对象的内容加上以下列表对象的内容 - 即[6]
。由于您将此新对象归因于mylist
,我们的场景会稍微改变,而mylist
不再指向list1
指向的同一对象:
我没有说的是mylist
是一个局部变量:它将在proc()
函数结束后消失。因此,当proc()
执行结束时,mylist
消失了:
由于没有其他变量指向mylist + [6]
生成的对象,它也会消失(因为垃圾收集器*会收集它):
请注意,最后,list1
指向的对象不会更改。
What happens when you call proc2()
当你打电话给proc2()
时,一切都会改变。首先,它是一样的:你创建一个列表......
...并将其作为参数传递给函数,该函数将生成局部变量:
但是,不是使用生成新列表的+
连接运算符,而是将append()
方法应用于现有列表。 append()
方法不会创建新对象;相反,它_改变现有的:
函数结束后,局部变量将消失,但由它和list1
指向的原始对象将被更改:
由于它仍然由list1
指出,原始列表不会被销毁。
编辑:如果你想看看你眼前发生的所有这些事情,只需去this radically amazing simulator:
*如果您不知道什么是垃圾收集器......那么,您将在了解自己的问题后立即发现。
python中的变量总是可以被认为是引用。当您使用参数调用函数时,您将传入对实际数据的引用。
当您使用赋值运算符(=
)时,您将指定该名称以引用一个全新的对象。因此,mylist = mylist + [6]
创建一个包含mylist的旧内容的新列表,以及6,并指定变量mylist以引用新列表。 list1仍指向旧列表,因此没有任何更改。
另一方面,当您使用.append时,实际上是将一个元素附加到变量引用的列表中 - 它不会为变量赋予任何新内容。所以你的第二个函数修改了list2引用的列表。
通常,在函数proc
的第一种情况下,如果您声明,您将只能通过赋值更改全局列表
global mylist
首先,并没有通过mylist
作为参数。但是,在这种情况下,您会收到一条错误消息,指出mylist
是全局的和本地的:name 'mylist' is local and global
。在proc
中发生的是在分配发生时创建本地列表。由于局部变量在函数结束时消失,因此当随后打印出来时,对本地列表的任何更改的影响都不会传播到程序的其余部分。
但是在第二个函数proc2
中,您通过附加而不是分配来修改列表,因此不需要global
关键字,并且列表中的更改显示在其他位置。
这种或那种形式是一个非常常见的问题。我解释了Python参数传递自己a couple days ago。基本上,其中一个创建一个新列表,另一个修改现有列表。在后一种情况下,引用列表的所有变量都“看到”变化,因为它仍然是同一个对象。
在第三行,你做到了这一点
list1=list1+[6]
所以,当你在上面的行之后做了下面的话,
print (list1)
你在start和proc过程中创建的print1打印了list1,它添加了list1 + [6],它在函数proc中创建了一个新列表。如果要追加[6],则不会创建新列表,而是将列表项追加到现有列表中。
但是,请记住。在第7行中,您再次创建了列表
list1 = [1,2,3,4]
现在你想通过显式调用它来打印list1,这将打印出你再次重新初始化而不是前一个的list1。
除了已经给出的全面答案之外,还值得注意的是,如果您需要与以下相同的语法:
mylist = mylist + [6]
...但仍希望列表“就地”更新,您可以这样做:
mylist += [6]
虽然它看起来像第一个版本一样,但实际上与以下相同:
mylist.extend([6])
(注意,extend
获取一个iterable的内容并逐个添加它们,而append
会获取它给出的任何内容并将其作为单个项添加。请参阅append vs. extend以获得完整的解释。)
以上是关于为什么+运算符不会在.append()的情况下更改列表?的主要内容,如果未能解决你的问题,请参考以下文章
String StringBuilder StringBuffer 的区别? 什么情况下用“+”运算符进行字符串连接比调用 StringBuffer/StringBuilder对象的 append(代