Python类中的Numpy Matrix表现出链接行为?

时间:2016-08-20 19:21:53

标签: python class numpy matrix

如果你在Python中创建一个类:

 import numpy as np
 class Foo:

    def __init__(self, data):
        self.data = data 
        self.data_copy = self.copy(self.data)

    def copy(self, data):
        a = []
        for e in data:
            a.append(e)
        return a

    def change(self, val):
        for i in range(0, len(self.data_copy)):
            self.data_copy[i] += val

然后创建类的实例,例如:

a = Foo([np.matrix([1,2,3]), np.matrix([5,6,7])])

现在,如果我们调用a.change(np.matrix([5,5,2]))函数,该函数只应修改self.data_copy列表,self.data列表也会随更改一起更新。看来,即使在制作新列表之后,两个列表中的Numpy矩阵仍然保持联系。

这在某些方面是一个很好的功能,但如果我传入一个普通的Python数字列表,它就不起作用。这是一个错误,还是Numpy矩阵被复制的副作用?如果是这样,用普通Python列表复制行为的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

当您进行“复制”时,您只需创建一个包含与旧列表相同对象的新列表。也就是说,当您遍历data时,您正在迭代对其中对象的引用,并且当您追加e时,您将附加引用而不是新对象或复制对象。因此,对这些对象的任何更改都将在引用它们的任何其他列表中可见。看起来你想要的是实际矩阵的副本。要执行此操作,请在copy方法中添加e之类的numpy.array(e, copy=True),而不是附加copy。这将创建矩阵的真实副本,而不仅仅是对旧矩阵的新引用。

更一般地说,Python对象实际上总是通过引用传递。这对于不可变对象(字符串,整数,元组等)无关紧要,但对于可以变异的列表,字典或用户定义的类,您需要制作显式副本。通常内置的+=模块,或者只是直接从旧模块构建一个新对象,就是你想要做的。

编辑:我现在明白你的意思了。我稍微误解了你原来的问题。你指的是= self + other改变矩阵对象而不是真正的+=。这只是+=如何适用于大多数Python集合类型的事实。 a = [1, 2, 3] b = a b += [4] >>> print(a) [1, 2, 3, 4] 实际上是一个单独的方法,与分配添加结果不同。您仍会在普通的Python列表中看到这种行为。

+=

您可以看到b正在改变原始对象,而不是创建新对象并设置b = b + [4] >>> print(a) [1, 2, 3] >>> print(b) [1, 2, 3, 4] 来引用它。但是如果你这样做:

+

这将具有所需的行为。集合的+=运算符(列表,numpy数组)确实返回了一个新对象,但=SUM((COUNTIF(A2:A209066,A2:A209066)=1)*1) 通常只是改变了旧对象。