我正在寻找适当的术语来描述这个集合对象的众所周知的属性,更重要的是,当变量用于引用它们的元素时,堆栈图的变化方式:
>>> x = 5
>>> l = [x]
>>> x += 1
>>> l
[5]
>>> x
6
列表对变量x
执行的操作的名称是什么,以防止它绑定到x
原始值的任何更改?屏蔽?共享结构?列表绑定?使用这些条款从谷歌搜索中找不到任何东西。
这是一个更详细的例子(但不幸的是没有定义)。
答案 0 :(得分:5)
列表对变量x执行的操作的名称是什么,以防止它绑定到x的原始值的任何更改?屏蔽?共享结构?列表绑定?使用这些条款从谷歌搜索中找不到任何东西。
因为列表不是做任何事情,并且它不是集合的属性。
在Python中,变量是名称。
>>> x = 5
这意味着:x
应为值5
的名称。
>>> l = [x]
这意味着:l
应该是获取x
名称(5
)的值,并使用该值创建一个元素列表所产生的值的名称( [5]
)。
>>> x += 1
x += 1
在这里被重写为x = x + 1
,因为整数是不可变的。您不能使值5
增加1,因为它将再次为5
。
因此,这意味着:x
将不再是其当前名称的名称,并开始成为数学表达式x + 1
产生的值的名称。即,6
。
这就是参考语义的发生方式。没有理由期望列表的内容发生变化。
现在,让我们看看价值语义会发生什么,用一种假设的语言看起来就像Python,但处理变量的方式与在C中处理它们的方式相同。
>>> x = 5
现在这意味着:x
是一块内存的标签,其中包含数字5
的表示。
>>> l = [x]
现在这意味着:l
是一块内存的标签,它包含一些列表结构(可能包括一些指针等),它们将以某种方式初始化,以便它代表一个包含1个元素的列表,具有值5
(从x
变量复制)。它不能在逻辑上包含x
,因为它是一个单独的变量,我们有值语义;所以我们存储了一份副本。
>>> x += 1
现在这意味着:增加x
变量中的数字;现在是6
。该列表再次不受影响。
无论您的语义如何,都不能以这种方式影响列表内容。期望更改列表内容意味着您的解释不一致。 (如果将代码重写为l = [5]; x = l[0]; x += 1
,这将变得更加明显。)
答案 1 :(得分:4)
我称之为所包含对象的“不变性”。
我认为你将你的情况与下面的情况进行比较:
x = []
l = [x]
x += [1]
print l # --> [[1]]
区别在于:
在这种情况下(可变的情况),你会改变列表x
中包含的原始对象l
。
但是,在您的情况下,您x
指向一个不可变对象(5
),然后将其添加到列表中。之后,此引用将替换为6
,但仅适用于x
,而不是列表。
所以x += <something>
要么修改x
,要么用另一个对象替换它,具体取决于对象类型的性质。
编辑:它也与列表的性质无关。您可以使用2个变量实现相同的目标:
x = 5
y = x
print x, y, x is y
x += 1
print x, y, x is y
VS
x = []
y = x
print x, y, x is y
x += [1]
print x, y, x is y
由于x
的不变性导致int
变为x is y
,导致x is y
变为假,而第二个变为x
,y
仍为真,因为对象(列表)发生了变异,{{1}}和{{1}}引用的对象的标识保持不变。
答案 2 :(得分:1)
list
在您的示例中对x
所做的唯一事情就是阅读它;它以其他方式与变量交互。事实上,由表达式[x]
生成的列表根本不会与变量x
进行交互。
如果你不得不为它引入一条行话,那就是价值捕获,或者只是独立。
我认为没有一个特殊术语的原因是它是(a)不是需要太多讨论的东西(b)是严格按值语义的一个方面,其中变量总是包含引用。那些类型的语义现在几乎是常态(除非通过引用实际命名包含对象的内存的变量)。我认为OP期待着名字或懒惰的语义。
答案 3 :(得分:1)
您所描述的行为与引用有关。如果你熟悉c
,你可能也熟悉“指针”。 c
中的指针可以使真正复杂化,而Python使用的数据模型可以极大地简化事情。但是在c
中有一些背景知识有助于理解Python在这里的行为,这与c
指针的行为密切相关。因此,“指针”,“引用”和“取消引用”都是与您所谈论的内容相关的所有术语,尽管它们都不是它的“名称”。也许最好的名字是“间接” - 虽然这有点过于抽象和包容;这是一种非常特殊的间接方式。也许“参考语义”?这是来自GvR自己使用该术语的演讲中的slide,而google search会出现一些有用的点击。
但如果你在c
中没有任何背景,这是我最好的解释。简而言之,您可以将Python名称视为指向对象的指针。因此,当您为某个值指定名称时,您将该名称“指向”该值。然后,当您为名称指定新值时,将其指向新值;但是旧的价值根本没有改变。在将名称视为指针时,这似乎很自然; “名称的值”被更改,但“值的值”不是。
有点令人困惑的是+=
行为不一致。当你对一个数字使用+=
时,使用上面的比喻结果很有意义:
x = 5
y = x
x += 1
print x, y
# 6 5
行为与x = x + 1
时的行为完全相同。
但有时+=
会以就地突变的方式过载。这是一个务实的,但略有不一致的习语:
x = [5]
y = x
x += [6]
print x, y
# [5, 6] [5, 6]
所以在这里,“值”的值被改变了。这实际上不是我最喜欢的Python,但它有很好的理由。
答案 4 :(得分:0)
您实际在做的是构建一个列表,其中一个元素引用与x
相同的对象。然后将新值绑定到x
,同时列表仍引用旧元素。这是因为+=
将引用返回给新对象(6
)并保留旧5
对象。 Python中的整数是 immutable 。