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
以指向某个内存位置的值。然后,当我初始化namenext_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
,因此无法说出它显示了什么。