将 numpy 数组附加到列表中 - 奇怪的事情

pee*_*ets 5 python arrays numpy list append

在树莓派上的 Raspbian 上使用 Spyder 3.1.3 中的 Python3.5.3。将两个 numpy 数组附加到名为“list0”的列表中,与分配的 numpy 数组“a”配合良好,例如:

import numpy as np

list0 = []
a = np.array([[1,2,3],[2,3,4]])
list0.append(a)
a = np.array([[11,12,13],[12,13,14]])
list0.append(a)

print("list0 =",list0)
Run Code Online (Sandbox Code Playgroud)

效果很好,作为输出提供(帖子的格式更好):

list0 = [ array([[ 1,  2,  3], [ 2,  3,  4]]), 
          array([[11, 12, 13], [12, 13, 14]]) ]
Run Code Online (Sandbox Code Playgroud)

使用循环将赋值替换为 a ,会发生奇怪的事情:

import numpy as np
a = np.empty((3), int)
list0 = []
for idx in range(4):    
    for i in range(3):
        a[i] = idx*10 + i
    print("idx =",idx,"; a =",a)
    list0.append(a)
print("list0 =",list0)
Run Code Online (Sandbox Code Playgroud)

第二行告诉 Python 使用的数组的形状(在我的原始情况下它是一个三维数组)。为了验证生成的名为“a”的数组被打印出来。将新填充的数组 'a' 附加到 'list0' 最终显示了最后一行的四倍。

idx = 0 ; a = [ 0  1  2]
idx = 1 ; a = [10 11 12]
idx = 2 ; a = [20 21 22]
idx = 3 ; a = [30 31 32]
list0 = [ array([30, 31, 32]), array([30, 31, 32]), 
          array([30, 31, 32]), array([30, 31, 32]) ] 
Run Code Online (Sandbox Code Playgroud)

我想 'list0' 只包含四次指向数组 'a' 的指针,该数组只存在于一个实例/内存范围中。

那么:如何将每个不同的数组 'a' 物理附加(复制?)到列表中?这是一个python错误还是仅仅是我对某些事情的误解?当然,我应该考虑更多的pythonian ;c)

谢谢你的帮助,彼得

tel*_*tel 10

问题

您将相同的数组附加a到您的list04 次。像数组一样a是可变对象,这意味着,除其他外,当您为它们分配值时,底层对象会发生变化。由于该数组在您的列表中出现了 4 次,这些更改(似乎)出现在 4 个不同的地方。

解决方案

您可以通过一个小的更改来修复您拥有的代码。将数组的副本附加到您的列表中,而不是数组本身:

import numpy as np
a = np.empty((3), int)
list0 = []
for idx in range(4):    
    for i in range(3):
        a[i] = idx*10 + i
    print("idx =",idx,"; a =",a)
    list0.append(a.copy())
print("list0 =",list0)
Run Code Online (Sandbox Code Playgroud)

输出:

idx = 0 ; a = [0 1 2]
idx = 1 ; a = [10 11 12]
idx = 2 ; a = [20 21 22]
idx = 3 ; a = [30 31 32]
list0 = [array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]
Run Code Online (Sandbox Code Playgroud)

优化方案

Python/Numpy 提供了许多更好的方法(在使用更少的代码行和更快的运行速度方面)来初始化数组。对于像这样的一堆范围,这是一个合理的方法:

list0 = [np.arange(n*10, n*10+3) for n in range(4)]
print(list0)
Run Code Online (Sandbox Code Playgroud)

输出:

[array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]
Run Code Online (Sandbox Code Playgroud)

您也可以考虑仅使用单个 2D 数组代替数组列表。单个数组通常比列表中数组的异构混合更容易使用。这是你如何做到的:

arr0 = np.array([np.arange(n*10, n*10+3) for n in range(4)])
print(arr0)
Run Code Online (Sandbox Code Playgroud)

输出:

[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]
Run Code Online (Sandbox Code Playgroud)


Fsn*_*sn9 7

只需这样做:

list_to_append.append(np_array.copy())
Run Code Online (Sandbox Code Playgroud)

简而言之,numpy 数组或列表是可变对象,这意味着当您将 numpy 数组或列表分配给变量时,您真正分配的是对内存位置(也称为指针)的引用

在您的情况下,“a”是一个指针,因此您真正要做的是将“a”指向的内存位置的地址附加到 list0 ,而不是指针指向的实际值。因此,这意味着“list0”的每个新位置在附加之后,结果都是相同的内存地址:“a”。

所以,而不是:

list0.append(a)
Run Code Online (Sandbox Code Playgroud)

您调用“a”的 copy() 方法,为“a”的新值创建一个新的内存位置并返回它:

list0.append(a.copy())
Run Code Online (Sandbox Code Playgroud)