我不知道幕后发生了什么,但是对 NumPy 数组和 Python 列表中的项目的就地操作将返回相同的引用,当传递给函数时,IMO 可能会导致令人困惑的结果。
从 Python 开始
>>> a = [1, 2, 3]
>>> b = a
>>> a is b
True
>>> id(a[2])
12345
>>> id(b[2])
12345
... where是值在内存中12345
的唯一位置,与.id
a[2]
b[2]
所以a
并b
参考内存中的相同列表。现在尝试对列表中的项目进行就地添加。
>>> a[2] += 4
>>> a
[1, 2, 7]
>>> b
[1, 2, 7]
>>> a is b
True
>>> id(a[2])
67890
>>> id(b[2])
67890
因此,在列表中就地添加项目只会更改 index 处项目的值,2
但仍然引用相同的列表,尽管列表中的第 3 项被重新分配给新值,。重新分配解释了为什么如果和是整数(或浮点数)而不是列表,那么会导致重新分配,然后和会是不同的引用。但是,如果调用列表添加,例如:for和引用同一个列表,它不会重新分配;它们都将被附加。a
b
7
a = 4
b = a
a += 1
a
b
a
a += [5]
a
b
a
现在为 NumPy
>>> import numpy as np
>>> a = np.array([1, 2, 3], float)
>>> b = a
>>> a is b
True
同样,这些是相同的引用,并且就地运算符似乎与 Python 中的 list 具有相同的效果:
>>> a += 4
>>> a
array([ 5., 6., 7.])
>>> b
array([ 5., 6., 7.])
在地方添加ndarray
更新参考。这与numpy.add
在新引用中创建副本的调用不同。
>>> a = a + 4
>>> a
array([ 9., 10., 11.])
>>> b
array([ 5., 6., 7.])
借用引用的就地操作
我认为这里的危险是如果引用被传递到不同的范围。
>>> def f(x):
... x += 4
... return x
参数引用x
被传递到f
不复制的范围内,实际上更改了该引用的值并将其传回。
>>> f(a)
array([ 13., 14., 15.])
>>> f(a)
array([ 17., 18., 19.])
>>> f(a)
array([ 21., 22., 23.])
>>> f(a)
array([ 25., 26., 27.])
对于 Python 列表也是如此:
>>> def f(x, y):
... x += [y]
>>> a = [1, 2, 3]
>>> b = a
>>> f(a, 5)
>>> a
[1, 2, 3, 5]
>>> b
[1, 2, 3, 5]
IMO 这可能会令人困惑,有时难以调试,因此我尝试仅对属于当前范围的引用使用就地运算符,并尝试小心借用引用。