在Python中将一个变量的值赋给另一个变量时会发生什么?
这是我学习python的第二天(我知道C ++和一些OOP的基础知识。),我对python中的变量有些轻微的混淆。
以下是我目前的理解方式:
Python变量是对象的引用(或指针?)(它们是可变的或不可变的)。 当我们有类似num = 5的东西时,在内存中的某处创建不可变对象5,并在某个名称空间中创建名称 - 对象引用对num。 当我们有a = num时,没有被复制,但现在两个变量都引用同一个对象,spam被添加到同一个命名空间。
这就是我的书,用Python自动化无聊的东西,让我感到困惑。 因为它是一本新手书,它没有提到对象,命名空间等,它试图解释以下代码:
>>> spam = 42
>>> cheese = spam
>>> spam = 100
>>> spam
100
>>> cheese
42
它提供的解释与C ++书籍完全相同,我不满意,因为我们正在处理对象的引用/指针。 所以在这种情况下,我想在第3行中,由于整数是不可变的,spam被分配了一个全新的指针/引用到内存中的不同位置,即它最初指向的内存未被修改。 因此我们有cheese引用spam所指的初始对象。这是正确的解释吗?
8个解决方案
78 votes
作为C ++开发人员,您可以将Python变量视为指针。
因此,当您编写cheese时,这意味着您“指定指针”(先前指向对象spam)指向对象42。
早些时候,cheese被指定为指向spam所指向的同一对象,当时恰好是42。 由于您尚未修改cheese,因此仍指向42。
在这种情况下,不变性与它无关,因为指针赋值不会改变被指向的对象的任何内容。
Jonas Adler answered 2019-06-07T00:19:31Z
20 votes
我看到的方式有一种语言的不同观点。
“语言律师”的观点。
“实用程序员”的观点。
“实施者”的观点。
从语言律师的角度来看,python变量总是“指向”一个对象。 但是,与Java和C ++不同,==< => =等的behvaiour取决于变量所指向的对象的运行时类型。 此外,在python内存管理由语言处理。
从实际的程序员角度来看,我们可以将整数,字符串,元组等不可变*对象而非直接值视为无关紧要的细节。 例外情况是,当存储大量的数值数据时,我们可能希望使用可以直接存储值的类型(例如numpy数组),而不是最终会有一个充满对微小对象的引用的数组的类型。
从实施者的角度来看,大多数语言都有某种假设规则,如果指定的行为是正确的,那么实施是正确的,无论事情是如何实际完成的。
所以,从语言律师的角度来看,你的解释是正确的。 从实际程序员的角度来看,你的书是正确的。 实现实际上取决于实现。 在cpython中,整数是真实对象,尽管从缓存池中获取小值整数而不是重新创建。 我不确定其他实现(例如pypy和jython)是做什么的。
*注意这里可变对象和不可变对象之间的区别。 对于一个可变对象,我们必须小心处理它“像一个值”,因为其他一些代码可能会改变它。 对于不可变对象,我们没有这样的顾虑。
plugwash answered 2019-06-07T00:20:57Z
19 votes
这是正确的你可以或多或少的变量作为指针。 但是,示例代码将有助于解释这实际上是如何工作的。
首先,我们将大量使用a功能:
返回对象的“标识”。 这是一个整数,在该生命周期内保证该对象是唯一且恒定的。 具有非重叠生存期的两个对象可以具有相同的id()值。
这可能会在您的机器上返回不同的绝对值。
考虑这个例子:
>>> foo = 'a string'
>>> id(foo)
4565302640
>>> bar = 'a different string'
>>> id(bar)
4565321816
>>> bar = foo
>>> id(bar) == id(foo)
True
>>> id(bar)
4565302640
你可以看到:
原始foo / bar具有不同的id,因为它们指向不同的对象
当bar被分配给foo时,它们的id现在是相同的。 这类似于它们都指向你在制作C ++指针时看到的内存中的相同位置
当我们更改foo的值时,会将其分配给不同的id:
>>> foo = 42
>>> id(foo)
4561661488
>>> foo = 'oh no'
>>> id(foo)
4565257832
一个有趣的观察结果是整数隐含地具有高达256的此功能:
>>> a = 100
>>> b = 100
>>> c = 100
>>> id(a) == id(b) == id(c)
True
但是超过256,这不再是真的:
>>> a = 256
>>> b = 256
>>> id(a) == id(b)
True
>>> a = 257
>>> b = 257
>>> id(a) == id(b)
False
但是将a分配给b确实会使id与之前显示的相同:
>>> a = b
>>> id(a) == id(b)
True
enderland answered 2019-06-07T00:22:34Z
16 votes
Python既不是pass-by-reference,也不是pass-by-value。 Python变量不是指针,它们不是引用,它们不是值。 Python变量是名称。
如果你需要相同的短语类型,或者可能是“按对象传递”,可以将它想象为“按别名传递”,因为你可以从指示它的任何变量中改变同一个对象,如果它是可变的,但是重新分配 变量(别名)仅更改一个变量。
如果有帮助:C变量是您将值写入的框。 Python名称是您放在值上的标记。
Python变量的名称是全局(或本地)命名空间中的一个键,它实际上是一个字典。 底层值是内存中的某个对象。 赋值给该对象命名。 将一个变量赋值给另一个变量意味着两个变量都是同一个对象的名称。 重新分配一个变量会更改该变量命名的对象,而不会更改其他变量。 您已移动标记但未更改上一个对象或其上的任何其他标记。
在CPython实现的底层C代码中,每个Python对象都是PyObject*,所以如果你只有指向数据的指针(没有指针到指针,没有直接传递的值),你可以把它想象成像C一样工作。
你可以说Python是值传递,其中值是指针......或者你可以说Python是传递引用,其中引用是副本。
David Heyman answered 2019-06-07T00:23:40Z
10 votes
当您运行spam = 100时,python在内存中创建另一个对象但不更改现有对象。 所以你仍然有指针cheese到42和spam到100
Oleksandr Dashkov answered 2019-06-07T00:24:12Z
8 votes
spam = 100行中发生的事情是用另一个指向另一个对象的指针(类型int,值100)替换先前的值(指向23811796519695165类型的对象的值为42)
bakatrouble answered 2019-06-07T00:24:45Z
8 votes
正如@DeepSpace在评论中提到的那样,Ned Batchelder在博客中对变量(名称)和值的分配做了很好的解释,并在PyCon 2015上发表了关于Python名称和值的事实和神话的演讲。 它可以让任何关注程度的Pythonistas都具有洞察力。
pylang answered 2019-06-07T00:25:17Z
1 votes
存储spam = 42时,它会在内存中创建一个对象。 然后你分配cheese = spam,它将spam引用的对象分配给cheese。最后,当你更改spam = 100时,它只更改spam对象。 所以cheese = 42。
Md. Rezwanul Haque answered 2019-06-07T00:25:50Z