我偶尔会使用numpy
,我试图在如何矢量化操作方面变得更聪明。我正在阅读一些代码并试图理解以下内容的语义:
arr_1[:] = arr_2
在这种情况下,
我知道在 arr[:, 0]
中,我们选择数组的第一列,但我对arr_1[:] = arr_2
和arr_1 = arr_2
之间的区别感到困惑
你的问题涉及基本的Python语法和numpy
具体细节的混合。 在许多方面,列表是相同的,但不完全一样。
arr[:, 0]
返回arr
的第一列(视图),arr[:,0]=10
将该列的值设置为 10。
arr[:]
返回arr
(alist[:]
返回列表的副本)。 arr[:]=arr2
执行就地替换;将 arr
的值更改为 arr2
的值。 arr2
的值将根据需要进行广播和复制。
arr=arr2
设置arr
变量指向的对象。 现在arr
和arr2
指向同一件事(无论是数组、列表还是其他任何东西)。
arr[...]=arr2
在复制所有数据时也有效
在交互式会话中播放这些操作。 尝试arr2
形状的变化,以查看值是如何广播的。 还要选中id(arr)
以查看变量指向的对象。 arr.__array_interface__
查看数组的数据缓冲区。 这有助于区分视图和副本。
arr_1[:] = ...
更改arr_1
引用的现有列表对象的元素。
arr_1 = ...
使名称arr_1
引用不同的列表对象。
主要区别在于,如果其他名称也引用原始列表对象,会发生什么情况。如果是这种情况,那么前者会更新两个名称所指的东西;而后者改变了一个名称所指的内容,而另一个名称则保留了原始事物。
>>> a = [0]
>>> b = a
>>> a[:] = [1]
>>> print(b)
[1] <--- note, change reflected by a and b
>>> a = [2]
>>> print(b)
[1] <--- but now a points at something else, so no change to b
也许最好通过使用id
来检查每个变量的内存位置来理解。
import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
>>> id(arr1)
4595568512
>>> id(arr2)
4595566192
# Slice assignment
arr1[:] = arr2
>>> arr1
array([4, 5, 6])
>>> id(arr1) # The object still points to the same memory location of `arr1`.
4595568512
# Reassignment.
arr1 = arr2
>>> id(arr1) # The object is now pointing to the object located to where `arr2` points.
4595566192
使用 arr_1[:] = arr_2
是 arr_1.__setitem__(slice(None, None), arr_2)
的快捷方式。 使用而不是arr_1 = arr_2
的原因是当你使用__setitem__
时,你正在修改arr_1
,而当你说arr_1 = arr_2
时,你正在重新定义arr_1
。 因此,使用 __setitem__
将修改对arr_1
对象的其他引用,而不仅仅是重新定义arr_1
。