我正在通过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并没有显示,但是当它不在函数中时它会显示吗?
答案 0 :(得分:15)
所以在一个函数中,向集合中添加6并没有显示,但是当它不在函数中时它会显示吗?
不,这不是发生的事情。
当您执行mylist = mylist + [6]
时,您实际上是在创建一个全新的列表并将其放在本地mylist
变量中。执行该函数后,此mylist
变量将消失,新创建的列表也将消失。
OTOH执行mylist.append(6)
时不创建新列表。您将获得mylist
变量中的列表,并将新元素添加到同一列表中。结果是列表(由list2
指向)也将自行更改。 mylist
变量将再次消失,但在这种情况下,您更改了原始列表。
让我们看看更直观的解释是否可以帮助您:)
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
指向的对象不会更改。
proc2()
致电proc2()
时,一切都会发生变化。首先,它是一样的:你创建一个列表......
...并将其作为参数传递给函数,该函数将生成局部变量:
但是,不是使用生成新列表的+
并置运算符,而是将append()
方法应用于现有列表。 append()
方法不会创建新对象;相反,它改变现有的:
在函数结束后,局部变量将消失,但是它和list1
指向的原始对象将会被更改:
由于list1
仍指向它,原始列表不会被销毁。
编辑:如果你想看看发生在之前发生的所有这些事情,请转到this radically amazing simulator:
*如果您不知道什么是垃圾收集器......那么,您将在了解自己的问题后立即发现。
答案 1 :(得分:3)
python中的变量总是可以被认为是引用。当您使用参数调用函数时,您将传递对实际数据的引用。
当您使用赋值运算符(=
)时,您将指定该名称以引用一个全新的对象。因此,mylist = mylist + [6]
创建一个包含mylist的旧内容的新列表,以及6,并指定变量mylist以引用新列表。 list1仍指向旧列表,因此没有任何更改。
另一方面,当你使用.append时,实际上是将一个元素附加到变量引用的列表中 - 它没有为变量赋予任何新内容。所以你的第二个函数修改了list2引用的列表。
答案 2 :(得分:2)
通常,在函数proc
的第一种情况下,如果声明了
global mylist
首先,并没有将mylist
作为参数传递。但是,在这种情况下,您将收到mylist
全局和本地的错误消息:
name 'mylist' is local and global
。 proc
中发生的事情是在分配发生时创建本地列表。由于局部变量在函数结束时消失,因此随后打印出来时,对本地列表的任何更改的影响都不会传播到程序的其余部分。
但是在第二个函数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完整的解释。)