Python NumPy Ndarray真的是可变的吗?

Python NumPy Ndarray真的是可变的吗?,python,numpy,Python,Numpy,这是我的第一个代码片段。运行时,它不会抛出断言错误 import numpy as np this_arr = np.ones(10) next_arr = this_arr next_arr *= 2 assert np.array_equal(this_arr, next_arr) import numpy as np this_arr = np.ones(10) next_arr = this_arr next_arr = next_arr * 2 assert np

这是我的第一个代码片段。运行时,它不会抛出断言错误

import numpy as np


this_arr = np.ones(10)

next_arr = this_arr

next_arr *= 2

assert np.array_equal(this_arr, next_arr)
import numpy as np


this_arr = np.ones(10)

next_arr = this_arr

next_arr = next_arr * 2

assert np.array_equal(this_arr, next_arr)
这是我的第二个代码片段。运行时,它会抛出断言错误

import numpy as np


this_arr = np.ones(10)

next_arr = this_arr

next_arr *= 2

assert np.array_equal(this_arr, next_arr)
import numpy as np


this_arr = np.ones(10)

next_arr = this_arr

next_arr = next_arr * 2

assert np.array_equal(this_arr, next_arr)
我对这种行为感到困惑


我对第一个代码段的理解是,我初始化名称
this\u arr
以指向某个内存位置的值。然后,当我初始化name
next_arr
时,指向同一内存位置的同一个值。因此,当我更改由
next\u arr
指向的值时,
this\u arr
指向的值也应该更改。这种行为就是Ned Batchelder创造的“可变的Presto Chango”


但是,第二个代码段的行为并非如此。起初,我认为可能是
*=
操作符在某种程度上没有改变值在内存中的位置,而
*
操作符却改变了。但后来我回顾了第一个片段,发现
this\u arr
next\u arr
的内存位置在这里也不同!鉴于此,程序如何“知道”更改
此\u arr
的值以匹配更改的
下一个\u arr
的值?另外,为什么程序“不知道”更改第二个代码段中的值

编辑:作为一个后续问题:所以,即使next_arr和this_arr具有不同的内存位置,python已经初始化的这两者之间还是有一些潜在的连接


谢谢

当您初始化next\u arr=this\u arr时,它实际做的是将this\u arr位置的值复制到next\u arr的新位置。这是我对这段代码的理解,否则这种行为就不可能了

我更喜欢从对象和引用的角度来讨论,而不是从值的角度。因此,我将您的第一个代码描述为:

这将创建一个
ndarray
对象,并将其(或对其的引用)分配给
This\u arr

this_arr = np.ones(10)
next_arr = this_arr
并将相同的引用分配给下一个\u arr:

this_arr = np.ones(10)
next_arr = this_arr
因此
next\u arr
this\u arr
引用相同的对象

然后对数组对象进行“就地”更改。使用哪个名字并不重要

next_arr *= 2
这两个名称仍然引用同一个数组对象。(在封面下进行了一些缓冲,但数组对象和数据缓冲区位置保持不变)。另一个可变的更改是
next\u arr[1]=10
(对于列表对象也是如此)

乘法生成一个新的数组对象。分配给
next\u arr
,断开与先前引用对象(该
this\u arr
仍然引用)的任何链接

如果
id(this\u arr)
id(next\u arr)
相同,则引用对象。大致上,
id
是一个位置,但与
c
中的指针不同。但要小心随着时间的推移比较ID;它们可以重复使用


arr.\uuuu数组\u接口\uuuu
是另一个方便的工具。If有一个
data
键,告诉我们数组的底层数据缓冲区的位置。但要了解数组的存储方式,以及
查看
复制

之间的区别,首先,我认为*=运算符可能在某种程度上不会更改值在内存中的位置,而*运算符会更改。根据以下内容,您是正确的:“如果可能,实际操作将在适当的位置执行,这意味着不创建新对象并将其分配给目标,而是修改旧对象。”“我对第一个代码段的理解是,我初始化名称this_arr以指向某个内存位置的值。“不,Python中的任何东西都不是这样工作的。从内存位置的角度考虑是非常没有帮助的。Python是一种高级语言。你的心智模型应该是关于对象的。你给变量
this\u arr
分配了
numpy.ndarray
对象。然后你给被引用的对象分配了
next\u array
通过
this\u array
,但在您将另一个对象分配给
next\u array
之后,由
next\u arr=next\u arr*2
创建的对象不是一个变异。但是
next\u arr*=2
是。@Jfacconi感谢您的评论!但是,在与我的调试器检查后,这个和next\u arr已经发生了变化两个代码段中的内存地址不同。鉴于此,当第一个代码段中的下一个更改时,此\u arr如何更改?在第一个示例中,它们具有相同的内存位置,在第二个示例中,它们没有。如何获得不同的内存位置,请提供一个可复制的示例,说明如何验证这一点(同样,这并不是思考事物的最佳方式,它们是相同的对象或不同的对象)。这对我来说没有多大意义。为了使第一个代码段不会抛出错误,这意味着在执行next_arr*=2之后,它的值会被复制回this_arr。是否正确?使用
initialize next_arr=this_arr
时,不会复制值。这只是一个简单的Python变量赋值。这不是correct,或者至少,没有明确说明。谢谢你的回复。我用assert(id(this_arr)==id(next_arr))替换了我对assert的调用。第一个代码段为每个数组生成了相同的ID值,第二个代码段为每个数组生成了不同的ID值。这是正确的!您知道PyCharm调试器给出的ID值和内存值之间的差异吗?虽然第一个代码段中两个数组的ID值相同,但我在下面的问题评论中描述的过程在内存中仍然产生不同的值。我没有使用
pycharm
,因此无法说出它显示了什么。