这是我的第一个代码片段。运行时,它不会抛出断言错误。import numpy as npthis_arr = np.ones(10)next_arr = this_arrnext_arr *= 2assert np.array_equal(this_arr, next_arr)这是我的第二个代码片段。运行时,它会抛出一个断言错误。import numpy as npthis_arr = np.ones(10)next_arr = this_arrnext_arr = next_arr * 2assert np.array_equal(this_arr, next_arr)这种行为让我感到困惑。我对第一个代码片段的理解是,我将名称初始化this_arr为指向某个内存位置的值。然后,当我初始化名称next_arr以指向相同内存位置的相同值时。因此,当我改变指向的值时next_arr,指向的值this_arr也应该改变。这种行为是 Ned Batchelder在此处创造的“Mutable-Presto-Chango” 。但是,第二个代码片段不会以这种方式运行。起初,我认为也许*=运算符在操作符更改时不会以某种方式更改值在内存中的位置*。但是后来我回过头来看第一个片段,发现 和 的内存位置在this_arr这里next_arr也不同!鉴于此,程序如何“知道”更改值this_arr以匹配已更改的值next_arr?另外,为什么程序“不知道”更改第二个代码片段中的值?编辑:作为后续问题:所以即使 next_arr 和 this_arr 有不同的内存位置,python 初始化的两者之间有一些潜在的联系?
2 回答
跃然一笑
TA贡献1826条经验 获得超6个赞
我更喜欢谈论对象和引用,而不是价值观。所以我会把你的第一个代码描述为:
这将创建一个ndarray
对象,并将其(或对它的引用)分配给this_arr
:
this_arr = np.ones(10)
并将相同的引用分配给next_arr
:
next_arr = this_arr
所以next_arr
和this_arr
引用同一个对象。
然后对数组对象进行“就地”更改。使用哪个名称并不重要。
next_arr *= 2
这两个名称仍然引用同一个数组对象。(在幕后做*=
一些缓冲,但数组对象和数据缓冲区位置保持不变)。另一个可变的变化是next_arr[1] = 10
(对于列表对象也是如此)。
和
next_arr = next_arr * 2
乘法生成一个新的数组对象。那被分配给next_arr
,打破了与先前引用对象(this_arr
仍然引用)的任何链接。
如果id(this_arr)
和id(next_arr)
相同,则引用该对象。大致id
是一个位置 - 但与c
. 但要注意随着时间的推移比较 id;它们可以被重复使用。
arr.__array_interface__
是另一个方便的工具。If 有一个data
键告诉我们数组的底层数据缓冲区位于何处。但是要了解您需要了解数组的存储方式以及 和 之间的view
区别copy
。
哔哔one
TA贡献1854条经验 获得超8个赞
当您初始化 next_arr=this_arr 时,它实际上所做的是将 this_arr 位置的值复制到 next_arr 的新位置。这是我对这段代码的理解,否则这种行为是不可能的
添加回答
举报
0/150
提交
取消