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

Python 将numpy数组追加到列表-奇怪的事情,python,arrays,list,numpy,append,Python,Arrays,List,Numpy,Append,使用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) 工作正

使用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)
工作正常,作为输出提供(对于帖子来说格式更好一些):

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

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错误还是仅仅是我对某些东西的误解?当然,我应该多想想蟒蛇;(c)

谢谢你的帮助,彼得解决了这个问题 您将同一数组
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])]
[array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]
[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]
优化解 Python/Numpy提供了许多更好的方法(在使用更少的代码行和运行更快方面)来初始化数组。对于这样的范围,这里有一个合理的方法:

list0 = [np.arange(n*10, n*10+3) for n in range(4)]
print(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])]
[array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]
[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]

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

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

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])]
[array([0, 1, 2]), array([10, 11, 12]), array([20, 21, 22]), array([30, 31, 32])]
[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]
只要这样做:

list\u to\u append.append(np\u array.copy())
简而言之,numpy数组或列表是可变对象,这意味着当您将numpy数组或列表分配给变量时,实际分配的是对内存位置的引用,也就是指针

在您的例子中,“a”是一个指针,所以您真正要做的是在list0中附加一个地址到“a”所指向的内存位置,而不是指针所指向的实际值。 因此,这意味着“list0”的每个新位置在附加后都是相同的内存地址:“a”

因此,不是:

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

list0.append(a.copy())

将可变对象添加到列表时,这是一个常见问题。该列表存储指向该对象的指针,在本例中,该指针在每个循环中都是相同的
a
需要在每次迭代中都是一个新数组。可以使用
a=idx*10+np.arange(3)
保存迭代。这是对Python语义的根本误解。阅读以下内容:在一种情况下,您创建两个不同的数组,并将其附加到列表中;在另一种情况下,您创建一个数组,并将其附加两次到列表中,因此列表包含对同一数组的两个引用。你可以使用<代码>拷贝> < /Cord>方法复制一个数组。@ HPululJ,我认为最好不要考虑Python中的指针(Python中不存在指针),而是用它自己的术语来学习语言。是的,这是真的,CPython实现使用了一些PyObject指针的原始数组,但它是一个实现detail@juanpa.arrivillaga,在numpy对象数据类型数组的上下文中,我认为指针或引用是最好的术语。与
ndarray
一样,数组的数据缓冲区存储
itemsize
元素,而不管它们引用(或指向)什么。这个术语一直延续到我对
列表的讨论中。这完全正确,但列表不是指针列表。指针与python真的一点关系都没有。非常感谢tel(和其他人)。在理解和消除我的想法方面帮助很大。.copy()立即工作正常。我的数据不是像示例中那样生成的,而是以二进制数组形式从pyserial接收的,并分发到3D矩阵。这些将被堆叠在一起以供以后评估。期待着将其应用到一个更像numpy和更快的方法中。如果你能解释为什么OP的方法没有像他们预期的那样运行,那将是一件好事,因为这也将帮助未来的读者解决这个问题。然后你可以解释为什么你的方法没有遇到这样的问题。虽然这段代码可能会解决这个问题,但如何以及为什么解决这个问题将真正有助于提高你的文章质量,并可能导致更多的投票。请记住,你是在将来回答读者的问题,而不仅仅是现在提问的人。请您的回答添加解释,并说明适用的限制和假设。关于要求对obove回答的解释:您的建议对我也很有帮助,如果我能回答问题,请不要忘记一些解释。上面贴了很好的解释;对我加深理解和进一步阅读有价值的想法。但Fsn9的回答会在一秒钟内帮助我,认为指针不是Python的思考方式;c) 谢谢你的建议。我想现在好多了。