变量的赋值

3
我对Python中的变量赋值问题感到困惑。我试着在互联网上查找关于这个问题的资料,包括页面,但是我仍然不理解它。
假设我将某个值赋给变量:
v = 2

Python在某个内存位置中保留了一个值为2的位置。我们现在知道如何通过给它分配一个变量名来访问该特定的内存位置:v
如果我们这样做:
v = v + 4

一个新的内存位置将被填充值为6(2+4),现在要访问这个值,我们将变量v绑定到它上面。
这是正确的吗,还是完全错误的?
那么初始值2在内存位置上会发生什么?它不再绑定到任何变量上,因此无法再访问该值?这是否意味着在接下来的几分钟内,垃圾收集器将释放该内存位置?
谢谢您的回复。
编辑: v = 2v = v + 2只是简单的例子。在我的情况下,我有一些非Python本地对象,它们的大小可以达到几十兆字节,甚至高达400兆字节。
很抱歉没有在一开始就清楚说明这一点。我不知道整数和其他类型对象之间有区别。
2个回答

3

你说得没错。实际上,Python会构建整数对象24。在第一个赋值中,解释器使v指向2对象。

在第二个赋值中,我们构造了一个对象6,并使v指向它,正如你所预期的那样。

接下来发生的事情取决于实现方式。使用对象表示连续的原子值的大多数解释器和编译器,将认识到2对象是一个小整数,很可能会再次使用,并且非常便宜维护 - 因此它不会被垃圾回收。通常,在代码中出现的文本不会被作为垃圾回收对象处理。


感谢您更新问题。是的,您没有引用的大型对象现在可以进行垃圾回收。


1
你的意思是“这种类型的大多数解释器和编译器”是什么?问题特指Python,据我所知它没有垃圾回收器。 - maxymoo
好的观点...尽管垃圾回收取决于实现方式。我们有一个会释放内存的实现;否则,我们的一些大数据应用程序将会出错。 - Prune
谢谢@Prune和@maxymoo。 为什么维基百科关于赋值的页面会说:赋值语句...将一个值复制到变量中。。赋值真的会将值复制到变量中吗?还是它实际上只是指向该值(在内存位置中)?这两个概念是不同的。这是链接: https://en.wikipedia.org/wiki/Assignment_%28computer_science%29 - marco
1
维基百科页面适用于许多编程语言。在Python中,复制的值是指向2的指针,而不是2本身。这是语言定义的一个重要细节。在大多数语言中,实际值被复制到变量的内存位置。对于Python来说,优势在于每个变量的主要位置的大小为一个内存字。 - Prune
谢谢。所以当Python复制指向某个内存位置的指针时,该对象的大小是无关紧要的吗?它可以是1kb或1gb,都一样吗?复制指针的速度会“完成”相同吗? - marco
正确:指针的复制将以恒定速度完成。然而,对象的构建取决于对象的特性。这里没有什么魔法:如果对一个包含10,000个元素的数组的每个元素进行微不足道的计算和复制修改,您仍然需要支付计算和空间成本。 - Prune

3

关于小整数(-5到256)的示例并不是最好的,因为它们以一种特殊的方式表示(例如,请参见此处)。

总体上来说,您对事情的流程是正确的,所以如果您有像下面这样的内容:

v = f(v)

以下事情会发生:
  • 由于评估f(v)(除了小整数或文字优化),一个新的对象被创建。
  • 这个新对象被绑定到变量v
  • 之前在v中的任何内容现在都是不可访问的,并且通常可能会很快被垃圾收集。

谢谢@aldanor。 当没有必要使用它时,使用v = v + someValue是一种不好的做法吗?例如,我可以这样写:v2 = v + someValue。但从垃圾收集的角度来看,即使我不必这样做,将右侧的表达式分配给先前定义的变量(在本例中为v)是否更好? - marco
1
除非名称遮蔽引入不必要的混淆(例如,将名称分配给与函数参数名称冲突的名称),否则这并不是一个真正的不良实践。在大多数情况下,这两个示例之间没有区别,因为垃圾回收不会立即发生,并且很有可能,在它发生时,无论如何都会收集v。我从未亲眼见过这种事情很重要的例子,所以除非您正在使用昂贵的大型对象进行回收,否则您不应该真正担心它。 - aldanor
明白了。我之前以为通过引入v = v + someValue可以节省内存空间。现在我知道这不是事实,并且可能会引起混淆,所以我不会使用这种语法。 感谢您的帮助@aldanor。 - marco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接