共享引用

未匹配的标注

到目前为止,已经学习了当单个变量被分配对象引用时会发生什么。现在向交互会话引入另一个变量然后观察对它的名称和对象会发生什么:

>>> a = 3
>>> b = a

键入这两个语句会产生图6-2中描绘的情形。第二个命令让Python创建了变量b;变量a正在被使用且这里没有被赋值,所以它被其引用的对象(3)所代替,然后b被设置为引用那个对象。最终结果是变量ab最后引用同样的对象(也就是说,指向同样的内存块)。

image-20230225135550556

图6-2. 在接下来运行赋值 b =a 后的名称和对象。变量b变成了对象3的引用。在内部,变量事实上是运行字面量表达式3所创建的对象内存空间的指针。

在Python中这个场景——多个名称引用同一个对象——通常被称为共享引用(且有时只是共享对象)。注意当这个场景发生时,名称a和b并不直接相互连接;事实上,在Python中在任何时候都没有办法将一个变量连接到另一个变量。相反,两个变量通过它们的引用指向同样的对象。

接下来,假设再用一个语句来扩展这个会话:

>>> a = 3
>>> b = a
>>> a = 'spam'

和所有Python赋值一样,这个语句简单地创建了一个代表字符串值'spam'的新对象且设置a来引用这个新对象。然而,它没有改变b的值;b仍然引用原来的对象(整数3)。最终引用结果如图6-3中所示。

image-20230225140103463

图6-3. 在最后运行赋值 a = 'spam' 后的名称和对象。变量a引用运行字面量表达式'spam'所创建的新对象(也就是,内存片段),但变量b仍然引用原来的对象3。因为这个赋值不是对象3的就地更改,它只改变了变量a,而没有改变b。

如果将b改为spam,同样类型的事情也将发生——赋值将只改变b,而非a。如果完全没有类型差异,这个行为也会发生。比如,考虑下面三个语句:

>>> a = 3
>>> b = a
>>> a = a + 2

在这个序列中,同样的事情发生了。如图6-2,Python让变量a引用对象3,让b引用和a一样的对象;和以前一样,最后的赋值将a设置为一个完全不同的对象(在本例中,是整数5,+ 表达式的结果)。它没有顺带改变b。事实上,在任何时候都没有办法覆盖对象3的值——如第4章中介绍的,整数不可变,所以决不能被就地修改。

思考这个场景的一种方式是不像其他语言,在Python中变量总是对象指针,而非可改变内存区域的标签:对一个变量设置一个新值不会改变原来的对象,而是会让这个变量去引用一个完全不同的对象。最终结果是对一个变量本身的赋值只能影响正在被赋值的这个单变量。然而,当可变对象和就地修改进入这个场景时,情况会在某种程度上改变;要看是怎么回事,继续前进。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~