为啥当我追加到其中的列表时,元组的内容会发生变化,但在更新变量时不会发生变化?
Posted
技术标签:
【中文标题】为啥当我追加到其中的列表时,元组的内容会发生变化,但在更新变量时不会发生变化?【英文标题】:Why does the content of a tuple changes when I append to a list inside of it but does not change when I update a variable?为什么当我追加到其中的列表时,元组的内容会发生变化,但在更新变量时不会发生变化? 【发布时间】:2012-06-17 01:37:44 【问题描述】:myVar = ["jhhj", "hgc"]
myTuple = ([1,2,3], [4,5,6], myVar)
myVar.append('lololol')
print myTuple
为什么以及如何在构造后通过追加来修改这个元组?
myVar = "lol"
myTuple = ([1,2,3], [4,5,6], myVar)
myVar = "lolol"
print myTuple
为什么会打印出([1,2,3], [4,5,6], "lol")
而不是([1,2,3], [4,5,6], "lolol")
?
【问题讨论】:
【参考方案1】:好吧,让我试着用一些图片来解释一下。
在 Python 中,一切都是对象。这些对象由变量引用。某些类型的对象,例如列表和元组,只是存储对其他对象的引用。
也就是说,当你执行时
myVar = ["jhhj", "hgc"]
myTuple = ([1,2,3], [4,5,6], myVar)
您或多或少会遇到这种情况:
每个对象都由一个框/矩形表示。我们有两个字符串对象,"jhhj"
和 "hgc"
。另外,我们有一个列表对象,由变量myVar
指向;此列表对象指向两个字符串对象。另外,我们有一个元组对象,由myTuple
引用;这个元组对象指向另外两个列表和myVar
引用的列表。
当你执行时
myVar.append('lololol')
会发生什么?好吧,列表对象(顺便提一下myVar
)开始引用另一个值,字符串对象"lololol"
:
请注意,myVar
仍然引用列表对象。发生的事情是列表对象改变了。您可以从myVar
或元组中查看此列表对象,您将看到具有相同更改的相同对象。
OTOH,当你执行时
myVar = "lol"
myTuple = ([1,2,3], [4,5,6], myVar)
你会得到这样的东西:
现在myVar
指向字符串对象"lol"
,并且元组在其第三个位置引用它。现在,如果你执行
myVar = "lolol"
你只是让myVar
指向另一个对象。元组对象仍然像以前一样指向"lol"
:
所以,如果你给一个变量赋予一个新值,它只会改变这个变量所指向的值。变量引用的先前值将仍然存在*,并且指向它的任何其他变量或对象将保持指向它。只是属性变量会改变。
PS:另外,I answered a vaguely related question some time ago。您可能会发现答案很有帮助。
* 除非是被垃圾回收器回收,不过这又是一段漫长的历史了。
【讨论】:
【参考方案2】:python 中的所有东西都是对象。
所以当你做你最初的任务时
myVar = "lol"
你给 myVar 一个对象“lol”的引用
然后创建一个元组。第三个槽中的这个元组引用了“lol”
然后您创建一个新对象“lolol”并给 myVar 一个对它的引用。元组保留其对“lol”的原始引用
【讨论】:
那么为什么在程序后面添加一个列表会修改原始元组? 您正在修改元组内的列表对象 你没有修改元组。您正在修改元组的列表成员。一个稍微不准确但有用的方式是:元组([1,2], [3,4])
真的是 (address_to_list1, address_to_list2)
您不能更改地址,但列表是独立的、可变的对象。【参考方案3】:
元组是不可变的,所以如果你想修改它的一个成员,你需要构造一个新的元组......
【讨论】:
【参考方案4】:元组是不可变的,但您可以像这样将它们连接在一起:
var a = (1, 2)
var b = a + (3, 4)
【讨论】:
程序后面的列表 myVar 怎么会修改原来的元组?【参考方案5】:在这两种情况下,当您创建元组时,您正在复制对当时 myvar
的任何对象的引用。
在第一种情况下,myvar
是一个可变对象。您可以在对对象的引用存储在元组中之后更改对象。
在第二种情况下,myvar
是一个不可变字符串。您无法更改对象,但可以更改 myvar
本身所指的内容。但这不会改变元组中包含的对象。
【讨论】:
【参考方案6】:其他答案中的一些重要观点我将不再重复,解释names和objects之间的区别。我认为缺少的只是说明某些 Python 代码何时对名称进行操作以及何时对对象进行操作。
您需要了解的关键是,唯一直接影响名称的是赋值语句[1]。赋值语句重新绑定名称以指向不同的对象。出现在 any 其他上下文中的名称只是在执行该行代码时该名称绑定到的任何对象的简单表示。
让我们看看您的示例中的这一行:
myTuple = ([1,2,3], [4,5,6], myVar)
myTuple
出现在赋值语句的左侧,所以 name myTuple
是在那里受到影响的。另一方面,myVar
在表达式内部,所以 object myVar
绑定到的是元组的第三个元素,不是名称 @987654326 @。
因此,name myVar
之后发生的任何事情都不会对元组产生任何影响。但只要元组的第三个元素和myVar
引用同一个对象,更改该object(通过myVar
或元组)显然会影响您查看时得到的结果对象通过任一引用。
[1] 对于高级学习,def
和 class
语句也是“赋值语句”(它们创建一个函数或一个类,然后将其分配给名称)。
此外,+=
、*=
等运算符有时是赋值语句,有时不是,具体取决于 LHS 上当前名称所指对象的类型: p>
myList = []
myList += ['this calls a method on a list object which mutates it in place; the name is not changed']
myInt = 1
myInt += 10 # This rebinds myInt to refer to a new object 11; the object 1 is not changed
【讨论】:
以上是关于为啥当我追加到其中的列表时,元组的内容会发生变化,但在更新变量时不会发生变化?的主要内容,如果未能解决你的问题,请参考以下文章