迭代和修改 numpy 数组列表保持数组不变

Iterating and modifying a list of numpy arrays leave arrays unchanged

考虑以下两个代码:

import numpy as np

mainlist = [np.array([0,0,0, 1]), np.array([0,0,0,1])]

for i in range(len(mainlist)):
    mainlist[i] = mainlist[i][0:2]

print(mainlist) # [array([0, 0]), array([0, 0])] => OK!

和:

import numpy as np

mainlist = [np.array([0,0,0, 1]), np.array([0,0,0,1])]

for element in mainlist:
    element = element[0:2]

print(mainlist) # [array([0, 0, 0, 1]), array([0, 0, 0, 1])] => WTF?

我想知道为什么在第二种情况下,数组保持不变。它甚至不会抛出有关可变性问题的错误。您能否准确解释第二个代码的行为是怎么回事?正确的做法是什么?

element 持有对数组的引用(因为您正在迭代列表,它也只是存储对数组的引用)而不是指向列表的指针。 element = element[0:2] 只是更改存储在 element 中的引用,而列表中的那个保持不变。您可以使用 id():

检查引用对象的身份
import numpy as np

mainlist = [np.array([0,0,0, 1]), np.array([0,0,0,1])]

ref_0 = id(mainlist[0])

for element in mainlist:
    element = element[0:2]

print(mainlist) # [array([0, 0, 0, 1]), array([0, 0, 0, 1])] => WTF?

# True: referenced object changed.
print(ref_0 == id(mainlist[0]))

通过执行 manlist[i],您正在主动将存储在位置 i 的列表中的引用更改为新的 数组视图 :

import numpy as np

mainlist = [np.array([0,0,0, 1]), np.array([0,0,0,1])]

ref_0 = id(mainlist[0])

for i in range(len(mainlist)):
    mainlist[i] = mainlist[i][0:2]

print(mainlist) # [array([0, 0]), array([0, 0])] => OK!

# False: referenced object changed.
print(ref_0 == id(mainlist[0]))

在第一种情况下,您实际上是使用索引位置修改列表的元素,因此更新了列表,但在第二种情况下,您只是获取了列表的元素,然后创建了一个新变量称为元素和更新元素但不更新列表中存在的实际值。因此,原始列表保持不变。

如果您想使用第二种方法更新列表值,您可以创建第二个列表并将元素追加到该列表中。

Python 对 reference 进行操作。在第二个示例中,element 是引用列表项(即 Numpy 数组)的循环变量。 element = element[0:2] 导致 element 引用另一个对象:新创建的视图对象。 element 稍后设置为另一个引用,临时视图被隐式删除。它不会改变初始 mainlist 列表,只会改变 element 引用。在第一个例子中,mainlist[i] = mainlist[i][0:2] 改变了 mainlist[i] 等原始的 mainlist 列表。该项目被修改为引用新创建的视图。 mainlist[i] 稍后不会被覆盖,所以您会看到更改。

显示此类问题的另一个示例是:

l = [[None]*2]*2  # [[None, None], [None, None]]
l[0][0] = 42      # [[42, None], [42, None]]

修改了两个项目,因为它们引用了同一个对象(即列表 [42, None])。你可以看到使用 id: id(l[1]) == id(l[1]).

变量名a --->(指向)np.array([0,0,0, 1])

变量名b --->(指向)np.array([0,0,0, 1])

变量名mainlist --->(指向)[a, b]

当你使用for element in mainlist:,

变量名element --->(指向)np.array([0,0,0, 1])


当您通过 element = np.array([])element 分配另一个值时,

element --->(指向)np.array([])

但是 mainlist 仍然指向 [a, b]


当你使用mainlist[0] = np.array([])时,你确实把np.array([])放在了mainlist的第一个位置,但是a仍然指向np.array([0,0,0, 1])