为什么当我附加到其中的列表时元组的内容会发生变化,但是当我更新变量时它没有改变?

时间:2012-06-14 02:49:56

标签: python list append tuples variable-assignment

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")

6 个答案:

答案 0 :(得分:7)

好吧,让我试着用一些图片来解释。

在Python中,一切都是对象。这些对象由变量引用。某些类型的对象(如列表和元组)只存储对其他对象的引用。

那说,当你执行

myVar = ["jhhj", "hgc"]
myTuple = ([1,2,3], [4,5,6], myVar)

您或多或少会遇到这种情况:

A tuple pointing to three lists; a list pointing to two strings

每个对象由方框/矩形表示。我们有两个字符串对象"jhhj""hgc"。此外,我们有一个列表对象,由变量myVar指向;此列表对象指向两个字符串对象。另外,我们有一个由myTuple引用的元组对象;此元组对象指向另外两个列表和myVar引用的列表。

执行时

myVar.append('lololol')

会发生什么?好吧,列表对象(偶然由myVar指出)开始引用另一个值,字符串对象"lololol"

A tuple pointing to three lists; a list pointing to two strings; a new string is added to the list

请注意myVar仍引用列表对象。发生的事情是列表对象已更改。您可以从myVar或从元组中查看此列表对象,您将看到具有相同更改的同一对象。

OTOH,执行时

myVar = "lol"
myTuple = ([1,2,3], [4,5,6], myVar)

你得到这样的东西:

A tuple pointing to two lists and a string, also pointed by a variable

现在myVar指向字符串对象"lol",并且元组在其第三个位置引用它。现在,如果你执行

myVar = "lolol"

你只是让myVar指向另一个对象。元组对象仍然像以前一样指向"lol"

A tuple pointing to two lists and a string, also pointed by a variable. The variable now references another string.

因此,如果将新值归因于变量,则只会更改此变量指向的值。变量引用的先前值仍然存在*,指向它的任何其他变量或对象将保持指向它。只是属性变量会改变。

PS:另外,I answered a vaguely related question some time ago。您可能会发现答案很有用。

*除非它是由垃圾收集器收集的,但这是另一个漫长的历史。

答案 1 :(得分:5)

python中的所有东西都是对象。

所以当你做原始作业时

myVar = "lol"

你给myVar一个对象的引用" lol"

然后创建一个元组。第三个插槽中的这个元组引用了" lol"

然后你创建一个新对象" lolol"并给myVar一个参考。元组保留其对" lol"

的原始引用

答案 2 :(得分:1)

元组是不可变的,所以如果你想修改它的一个成员,你需要构造一个新的元组......

答案 3 :(得分:1)

元组是不可变的,但您可以将它们连接在一起,如:

var a = (1, 2)
var b = a + (3, 4)

答案 4 :(得分:1)

在这两种情况下,当您创建元组时,您正在复制对当时myvar对象的引用。

在第一种情况下,myvar是一个可变对象。您可以在对象的引用存储在元组中后更改对象。

在第二种情况下,myvar是一个不可变的字符串。您无法更改对象,但可以更改myvar本身所指的内容。但这并没有改变元组中包含的对象。

答案 5 :(得分:1)

在其他答案中有一些重点我不会再次重复,解释名称对象之间的区别。我认为缺少的是当一些Python代码在名称上操作以及在对象上操作时拼写出来。

您需要了解的一件事是,直接影响名称的唯一事物是赋值语句[1]。赋值语句将名称重新绑定以指向其他对象。出现在任何其他上下文中的名称只是在执行该行代码时名称绑定到的任何对象的简单代表。

让我们看看你的例子中的这一行:

myTuple = ([1,2,3], [4,5,6], myVar)

myTuple出现在赋值语句的左侧,因此名称 myTuple正在那里受到影响。另一方面,myVar位于表达式中,因此对象 myVar被绑定到元组的第三个元素,名称myVar

因此, name myVar稍后发生的任何事情都不会对元组产生任何影响。但只要元组的第三个元素和myVar引用相同的对象,更改对象(通过myVar或元组)将明显影响你得到的内容当你通过参考文件看对象时。


[1]对于高级研究,defclass语句也是“赋值语句”(它们创建一个函数或类,然后将其分配给名称)。

此外,像+=*=等运算符有时 赋值语句,有时不是,取决于当前由名称引用的对象的类型LHS:

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