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

时间:2018-12-17 23:54:14

标签: python arrays list numpy append

在Raspbian Pi的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)

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

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

使用循环将分配替换为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)

第二行告诉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]) ] 

我想'list0'有时仅包含一个指向数组'a'的指针,该数组仅存在于一个实例/内存范围内。

所以:我如何物理上将每个不同的数组“ a”追加(复制?)到列表中?是python的bug还是仅仅是我对某些东西的误解?当然,我应该考虑更多的pythonian; c)

感谢您的帮助,彼得

2 个答案:

答案 0 :(得分:3)

问题

您要将相同的数组a附加到list0 4次。像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)

输出:

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])]

优化解决方案

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

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

输出:

[array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]

您可能还考虑仅使用单个2D数组来代替数组列表。一个单一的数组通常比列表中数组的异构混合更容易使用。操作方法如下:

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

输出:

[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]

答案 1 :(得分:1)

只需执行以下操作:

list_to_append.append(np_array.copy())

中,numpy数组或列表是可变对象,这意味着当您将numpy数组或列表分配给变量时,您实际上是在分配什么是对内存位置(也称为指针)的引用。

在您的情况下,“ a”是一个指针,因此您实际要做的是在list0后面附加一个由“ a”指向的内存位置的地址,而不是指针指向的实际值。 因此,这意味着“ list0”的每个新位置在追加后都会变成相同的内存地址:“ a”。

所以,而不是:

list0.append(a)

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

list0.append(a.copy())