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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45053461/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 16:39:09  来源:igfitidea点击:

What happens when you assign the value of one variable to another variable in Python?

pythonvariablesobject

提问by Ruslan Mushkaev

This is my second day of learning python (I know the basics of C++ and some OOP.), and I have some slight confusion regarding variables in python.

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

Here is how I understand them currently:

以下是我目前对它们的理解:

Python variables are references (or pointers?) to objects (which are either mutable or immutable). When we have something like num = 5, the immutable object 5is created somewhere in memory, and the name-object reference pair numis created in a certain namespace. When we have a = num, nothing is being copied, but now both variables refer to the same object and ais added to the same namespace.

Python 变量是对对象(可变或不可变)的引用(或指针?)。当我们有类似的东西时num = 5,不可变对象5在内存中的某处创建,名称-对象引用对num在某个命名空间中创建。当我们有 时a = num,什么都没有被复制,但现在两个变量都指向同一个对象并被a添加到同一个命名空间。

This is where my book, Automate the boring stuff with Python, confuses me. As it's a newbie book, it doesn't mention objects, namespaces, etc., and it attempts to explain the following code:

这就是我的书,用 Python 自动化无聊的东西,让我感到困惑的地方。由于是新手书,没有提到对象、命名空间等,尝试解释如下代码:

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

The explanation it offers is exactly the same as that of a C++ book, which I am not happy about as we are dealing with references/pointers to objects. So in this case, I guess that in the 3rd line, as integers are immutable, spamis being assigned an entirely new pointer/reference to a different location in memory, i.e. the memory that it was initially pointing to wasn't modified. Hence we have cheesereferring to the initial object referred to by spam. Is this the correct explanation?

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

采纳答案by Jonas Adler

As a C++ developer you can think of Python variables as pointers.

作为 C++ 开发人员,您可以将 Python 变量视为指针。

Thus when you write spam = 100, this means that you "assign the pointer", which was previously pointing to the object 42, to point to the object 100.

因此,当您编写时spam = 100,这意味着您“分配了之前指向对象的指针”42以指向对象100

Earlier on, cheesewas assigned to point to the same object as spampointed to, which happened to be 42at that time. Since you have not modified cheese, it still points to 42.

早些时候,cheese被分配指向与所指向的对象相同的对象spam,这恰好是42当时。既然你没有修改cheese,它仍然指向42

Immutability has nothing to do with it in this case, since pointer assignment does not change anything about the object being pointed to.

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

回答by bakatrouble

What is happening in spam = 100line is replacement of previous value (pointer to object of type intwith value 42) with another pointer to another object (type int, value 100)

正在发生的事情spam = 100是用另一个指向另一个对象的指针(类型,值)替换先前的值(指向类型int为 value 的对象的42指针)int100

回答by Oleksandr Dashkov

When you run spam = 100python create one more object in the memory but not change existing. so you still have pointer cheeseto 42 and spamto 100

当您运行spam = 100python 时,在内存中再创建一个对象但不更改现有对象。所以你仍然有指向cheese42 和spam100 的指针

回答by Md. Rezwanul Haque

When you store spam = 42, it creates an object in the memory. Then you assign cheese = spam, It assigns the object referenced by spamto cheese. And finally, when you change spam = 100, it changes only spamobject. So cheese = 42.

当您存储时spam = 42,它会在内存中创建一个对象。然后你赋值cheese = spam,它赋值给spamto引用的对象cheese。最后,当你改变时spam = 100,它只改变spam对象。所以cheese = 42

回答by plugwash

The way I see it there are different views of a language.

在我看来,对一种语言有不同的看法。

  • The "language lawyer" perspective.
  • The "practical programmer" perspective.
  • the "implementor" perspective.
  • “语言律师”的观点。
  • “实用程序员”的观点。
  • “执行者”的观点。

From the language lawyer perspective python variables always "point at" an object. However unlike Java and C++ the behvaiour of == <= >= etc depends on the runtime type of the objects that the variables point at. Furthermore in python memory management is handled by the language.

从语言律师的角度来看,python 变量总是“指向”一个对象。然而,与 Java 和 C++ 不同,== <= >= 等的行为取决于变量指向的对象的运行时类型。此外,python 内存管理由语言处理。

From a practical programmer perspective we can treat the fact that integers, strings, tuples etc are immutable* objects rather than straight values as an irrelevent detail. The exception is when storing large ammounts of numeric data we may want to use types that can store the values directly (e.g. numpy arrays) rather than types that will end up with an array full of references to tiny objects.

从实际程序员的角度来看,我们可以将整数、字符串、元组等是不可变*对象而不是直接值这一事实视为无关紧要的细节。例外情况是,当存储大量数字数据时,我们可能希望使用可以直接存储值的类型(例如 numpy 数组),而不是最终会得到一个充满对小对象的引用的数组的类型。

From an implementers perspective most languages have some sort of as-if rule such that if the specified behaviours are correct the implementation is correct regardless of how things are actually done under the hood.

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

So yes your explanation is correct from a language lawyer perspective. Your book is correct from a practical programmer perspective. What an implementation actually does depends on the implementation. In cpython integers are real objects though small value integers are taken from a cache pool rather than created anew. I'm not sure what the other implementations (e.g. pypy and jython) do.

所以是的,从语言律师的角度来看,您的解释是正确的。从实用程序员的角度来看,您的书是正确的。实现实际上做什么取决于实现。在 cpython 中整数是真实的对象,尽管小值整数是从缓存池中获取而不是重新创建。我不确定其他实现(例如 pypy 和 jython)是做什么的。

* note the distinction between mutable and immutable objects here. With a mutable object we have to be careful about treating it "like a value" because some other code might mutate it. With an immutable object we have no such concerns.

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

回答by enderland

It is correct you can more or less thing of variables as pointers. However example code would help greatly with explaining howthis actually is working.

您可以或多或少地将变量作为指针是正确的。然而,示例代码将极大地帮助解释这实际上是如何工作的。

First, we will heavily utilize the idfunction:

首先,我们将大量使用该id功能:

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

返回对象的“身份”。这是一个整数,保证在此对象的生命周期内是唯一且恒定的。生命周期不重叠的两个对象可能具有相同的 id() 值。

It's likely this will return different absolute values on your machine.

这很可能会在您的机器上返回不同的绝对值。

Consider this example:

考虑这个例子:

>>> foo = 'a string'
>>> id(foo) 
4565302640
>>> bar = 'a different string'
>>> id(bar)
4565321816
>>> bar = foo
>>> id(bar) == id(foo)
True
>>> id(bar)
4565302640

You can see that:

你可以看到:

  • The original foo/bar have different ids, because they point to different objects
  • When bar is assigned to foo, their ids are now the same. This is similar to them both pointing to the same location in memory that you see in making a C++ pointer
  • 原始的 foo/bar 有不同的 id,因为它们指向不同的对象
  • 当 bar 分配给 foo 时,它们的 ID 现在相同。这类似于它们都指向内存中的相同位置,您在创建 C++ 指针时会看到

when we change the value of foo, it is assigned to a different id:

当我们更改 foo 的值时,它会被分配给不同的 id:

>>> foo = 42
>>> id(foo)
4561661488
>>> foo = 'oh no'
>>> id(foo)
4565257832

An interesting observation too is that integers implicitly have this functionality up to 256:

一个有趣的观察结果是整数隐式具有此功能,最多可达 256:

>>> a = 100
>>> b = 100
>>> c = 100
>>> id(a) == id(b) == id(c)
True

However beyond 256 this is no longer true:

然而,超过 256 这不再是真的:

>>> a = 256
>>> b = 256
>>> id(a) == id(b)
True
>>> a = 257
>>> b = 257
>>> id(a) == id(b)
False

however assigning ato bwill indeed keep the id the same as shown before:

但是分配ab确实会保持 id 与之前显示的相同:

>>> a = b
>>> id(a) == id(b)
True

回答by David Heyman

Python is neither pass-by-reference or pass-by-value. Python variables are not pointers, they are not references, they are not values. Python variables are names.

Python 既不是按引用传递也不是按值传递。Python 变量不是指针,也不是引用,也不是值。Python 变量是名称

Think of it as "pass-by-alias" if you need the same phrase type, or possibly "pass-by-object", because you can mutate the same object from any variable that indicates it, if it's mutable, but reassignment of a variable (alias) only changes that one variable.

如果您需要相同的短语类型,或者可能需要“pass-by-object”,可以将其视为“pass-by-alias”,因为您可以从指示它的任何变量中改变相同的对象,如果它是可变的,但重新分配一个变量(别名)只会改变那个变量。

If it helps: C variables are boxes that you write values into. Python names are tags that you put on values.

如果有帮助:C 变量是您将值写入其中的框。Python 名称是您放在值上的标签。

A Python variable's name is a key in the global (or local) namespace, which is effectively a dictionary. The underlying value is some object in memory. Assignment gives a name to that object. Assignment of one variable to another variable means both variables are names for the same object. Re-assignment of one variable changes what object is named by that variable without changing the other variable. You've moved the tag but not changed the previous object or any other tags on it.

Python 变量的名称是全局(或本地)命名空间中的一个键,它实际上是一个字典。底层值是内存中的某个对象。赋值为该对象命名。将一个变量分配给另一个变量意味着两个变量都是同一个对象的名称。重新分配一个变量会更改该变量命名的对象,而不会更改其他变量。您已经移动了标签,但没有更改上一个对象或上面的任何其他标签。

In the underlying C code of the CPython implementation, every Python object is a PyObject*, so you can think of it as working like C if you only ever had pointers to data (no pointers-to-pointers, no directly-passed values).

在 CPython 实现的底层 C 代码中,每个 Python 对象都是一个PyObject*,因此如果您只有指向数据的指针(没有指向指针的指针,没有直接传递的值),您可以认为它像 C 一样工作。

you could say that Python is pass-by-value, where the values are pointers… or you could say Python is pass-by-reference, where the references are copies.

您可以说 Python 是按值传递,其中值是指针……或者您可以说 Python 是按引用传递,其中引用是副本。

回答by pylang

As @DeepSpace mentioned in the comments, Ned Batchelder does a great job demystifying variables (names) and assignments to values in a blog, from which he delivered a talk at PyCon 2015, Facts and Myths about Python names and values. It can be insightful for Pythonistas at any level of mastery.

正如@DeepSpace 在评论中提到的那样,Ned Batchelder 在一篇博客中很好地揭开了变量(名称)和值赋值的神秘面纱,他在 2015 年 PyCon 上发表了演讲,关于 Python 名称和值的事实和神话。对于任何掌握程度的 Pythonistas 来说,它都具有洞察力。

回答by Onur Tavasl?o?lu

numpy.copy() function page has an explanation

numpy.copy() 函数页面有说明

https://docs.scipy.org/doc/numpy/reference/generated/numpy.copy.html

https://docs.scipy.org/doc/numpy/reference/generated/numpy.copy.html

The example it gives is as follows:

它给出的例子如下:

Create an array x, with a reference y and a copy z:

创建一个数组 x,带有一个引用 y 和一个副本 z:

x = np.array([1, 2, 3])
y = x
z = np.copy(x)

Note that, when we modify x, y changes, but not z:

请注意,当我们修改 x 时,y 会发生变化,但 z 不会:

x[0] = 10
x[0] == y[0]
True
x[0] == z[0]
False

回答by Giorgos Myrianthous

In Python, a variableholds the referenceto the object. An objectis a chunk of allocated memory that holds a value and a header. Object's header contains its type and a reference counter that denotes the amount of times this object is referenced in the source code so that Garbage Collection can identify whether an object can be collected.

在 Python 中,变量保存对object引用。一个目的是分配的存储器的块保持一个值和一个首标。对象的头包含它的类型和一个引用计数器,它表示在源代码中引用这个对象的次数,以便垃圾收集可以识别一个对象是否可以被收集。

Now when you assign values to a variable, Python actually assigns referenceswhich are pointersto memory locations allocated to objects:

现在,当您为变量赋值时,Python 实际上会分配引用,这些引用指向分配给对象的内存位置的指针

# x holds a reference to the memory location allocated for  
# the object(type=string, value="Hello World", refCounter=1)

x = "Hello World" 

Now when you assign objects of different type to the same variable, you actually change the reference so that it points to a different object (i.e. different memory location). By the time you assign a different reference (and thus object) to a variable, the Garbage Collector will immediately reclaim the space allocated to the previous object, assuming that it is not being referenced by any other variable in the source code:

现在,当您将不同类型的对象分配给同一个变量时,您实际上会更改引用,使其指向不同的对象(即不同的内存位置)。当你为一个变量分配一个不同的引用(和对象)时,垃圾收集器将立即回收分配给前一个对象的空间,假设它没有被源代码中的任何其他变量引用:

# x holds a reference to the memory location allocated for  
# the object(type=string, value="Hello World", refCounter=1)

x = "Hello World" 

# Now x holds the reference to a different object(type=int, value=10, refCounter=1)
# and object(type=string, value="Hello World", refCounter=0) -which is not refereced elsewhere
# will now be garbage-collected.
x = 10

Coming to your example now,

现在来看看你的例子,

spamholds the reference to object(type=int, value=42, refCounter=1):

spam保存对 object(type=int, value=42, refCounter=1) 的引用:

>>> spam = 42

Now cheesewill also hold the reference to object(type=int, value=42, refCounter=2)

现在cheese还将持有对 object(type=int, value=42, refCounter=2) 的引用

>>> cheese = spam

Now spam holds a reference to a different object(type=int, value=100, refCounter=1)

现在垃圾邮件持有对不同对象的引用(type=int, value=100, refCounter=1)

>>> spam = 100
>>> spam
100

But cheese will keep pointing to object(type=int, value=42, refCounter=1)

但是奶酪会一直指向 object(type=int, value=42, refCounter=1)

>>> cheese
42