当你将一个variables的值赋给Python中的另一个variables时会发生什么?

这是我学习python的第二天(我知道C ++和一些OOP的基础知识),并且我对python中的variables有一些疑惑。

以下是我目前了解他们的方式:

Pythonvariables是对象的引用(或指针?)(可变或不可变)。 当我们有类似于num = 5东西时,不可变的对象5在内存中的某处被创build,并且名称对象引用对num被创build在一个特定的名字空间中。 当我们有a = num ,没有什么被复制,但现在这两个variables引用相同的对象和a被添加到相同的命名空间。

这是我的书, 用Python自动化枯燥的东西 ,让我困惑。 由于这是一本新手书,它没有提到对象,名字空间等,它试图解释下面的代码:

 >>> spam = 42 >>> cheese = spam >>> spam = 100 >>> spam 100 >>> cheese 42 

它提供的解释与C ++书完全一样,我不喜欢我们正在处理引用/指向对象的指针。 所以在这种情况下,我想在第三行中,因为整数是不变的, spam被分配一个全新的指针/引用到内存中的不同位置,即它最初指向的内存没有被修改。 因此,我们有cheese是指spam提到的最初的对象。 这是正确的解释吗?

作为一名C ++开发人员,您可以将Pythonvariables视为指针。

因此,当您写入spam = 100 ,这意味着您“指定先前指向对象42的指针”指向对象100

早些时候, cheese被指派为指向同一个spam指向的对象,当时恰好是42 。 由于你没有改造cheese ,它仍然指向42

在这种情况下,不变性与它无关,因为指针分配不会改变所指向的对象的任何内容。

我看到的方式对语言有不同的看法。

  • “语言律师”的视angular。
  • “实用程序员”的观点。
  • “实施者”的观点。

从语言律师的angular度来看,pythonvariables总是“指向”一个对象。 然而,与Java和C ++不同,== <=> =等的behvaiour依赖于variables指向的对象的运行时types。 而且在python中,内存pipe理由语言来处理。

从一个实际的程序员的angular度来看,我们可以把整数,string,元组等作为不可变对象而不是直接值作为一个无关紧要的细节。 当存储大量的数值数据时,我们可能希望使用可以直接存储值的types(例如numpy数组),而不是最后会有一个数组完全引用小对象的types。

从实现者的angular度来看,大多数语言都有某种as-if规则,如果指定的行为是正确的,那么无论实际情况如何,实现都是正确的。

所以,从语言律师的angular度来看,你的解释是正确的。 从实际的程序员angular度来看,你的书是正确的。 实现的实际操作取决于实现。 在cpython中,整数是真实的对象,尽pipe小数值整数是从caching池中取出的,而不是重新创build的。 我不确定其他的实现(例如pypy和jython)是做什么的。

*注意这里的可变对象和不可变对象的区别。 对于一个可变的对象,我们必须小心处理它“像一个值”,因为其他的代码可能会改变它。 对于一个不可改变的对象,我们没有这样的担心。

这是正确的,你可以或多或less的variables作为指针的东西。 然而,示例代码将有助于解释这实际上是如何工作。

首先,我们将大量使用id函数:

返回一个对象的“身份”。 这是一个整数,在整个生命周期中保证这个对象是独一无二的。 两个具有非重叠生命周期的对象可能具有相同的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 

一个有趣的观察也是整数隐含有这个function高达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 

Python既不是通过引用也不是传值。 Pythonvariables不是指针,它们不是引用,它们不是值。 Pythonvariables是名字 。

如果你需要相同的短语types,或者可能是“传递对象”,可以把它看作“传递别名”,因为你可以从任何指示它的variables中改变同一个对象,如果它是可变的,但是重新分配一个variables(别名)只改变一个variables。

如果有帮助:Cvariables是您写入值的框。 Python的名字是你放在值上的标签。

Pythonvariables的名称是全局(或本地)名称空间中的一个键,它实际上是一个字典。 基础值是内存中的某个对象。 赋值给这个对象一个名字。 将一个variables赋值给另一个variables意味着两个variables都是同一个对象的名称。 重新赋值一个variables会改变该variables所指定的对象,而不会改变其他variables。 你已经移动了标签,但没有改变以前的对象或任何其他标签。

在CPython实现的底层C代码中,每个Python对象都是一个PyObject* ,所以如果你只有指向数据的指针(没有指向指针的指针,没有直接传递的值) 。

你可以说Python是通过值的,值是指针…或者你可以说Python是通过引用,其中的引用是副本。

当你运行spam = 100 python在内存中创build一个更多的对象,但不会改变现有的。 所以你仍然有指针cheese 42和spam 100

spam = 100行中发生的情况是用另一个指向另一个对象的指针(types为int ,值为100 )replace先前的值(指向inttypes的对象的值为42

正如评论中提到的@DeepSpace,Ned Batchelder在博客中做了很多神秘的variables(名称)和值赋值工作,他在PyCon 2015上发表了关于Python名称和价值观的事实和神话 。 它可以在任何级别的掌握Pythonistas的洞察力。

当你存储spam = 42 ,它会在内存中创build一个对象。 然后你分配cheese = spam ,它把被spam引用的对象分配给cheese 。 最后,当你改变spam = 100 ,它只会改变spam对象。 所以cheese = 42