为什么这个numpy属性突然在实例之间共享

时间:2017-12-02 16:00:03

标签: python-3.x numpy attributes shared-ptr instantiation

在Linux下使用python 3.6和numpy 1.12.1时,我偶然发现了奇怪的行为。

我有一个self.count属性,我用np.array([0.0, 0.0, 0.0])初始化。我希望self.count的行为与任何其他属性一样,并且每个类实例都有自己的值。

但是,在下面的代码中,当我使用

时使用addPixel方法
self.count += (1.0, 1.0, 1.0)

对于类CumulativePixel的所有实例,self.count属性都会增加。我想知道为什么会发生这种情况以及为什么我这样做时会修复:

self.count = self.count + (1.0, 1.0, 1.0)

代替。

import numpy as np

class CumulativePixel(object):
    '''
    class adds rgb triples and counts how many have been added
    '''

    def __init__(self, rgb = (0,0,0), count=np.array([0.0, 0.0, 0.0]) ):
        '''
        Constructor
        rgb sum is stored as two values. The integer part plus float part
        they are stored in a 2x3 matrix where the first row are integer
        parts and the second row are float parts. The code always tries to 
        make sure that float part is below 1.0
        '''
        self.rgb = np.array( [np.fmod(rgb, (1,1,1)).astype(float), (rgb - np.fmod(rgb, (1,1,1)))] )
        self.count = count

    @staticmethod   
    #for now only works for positve numbers 
    def _pixeladdition (disassembled, rgb):
        disassembled += np.array( [np.fmod(rgb, (1,1,1)).astype(float), (rgb - np.fmod(rgb, (1,1,1)))] )

        fpart = np.fmod(disassembled[0], (1,1,1))
        overflowpart = disassembled[0]-fpart
        disassembled[0]=fpart
        disassembled[1]+=overflowpart

        return disassembled

    def addPixel(self, rgb):
        self.rgb = self._pixeladdition(self.rgb, rgb)     
        # += would globalize self.count into all instances! why ???
        self.count = self.count + (1.0, 1.0, 1.0)

    def getAvgPixel(self, multiply = (1.0, 1.0, 1.0), add = (0.0, 0.0, 0.0), roundpx = False):
        if 0.0 in self.count: return (0.0, 0.0, 0.0)
        averagepixel = np.sum(self._pixeladdition((self.rgb/self.count), add)*multiply, axis=0)

        if roundpx: averagepixel = np.round(averagepixel).astype(int)

        return averagepixel

    def getSums(self):
        return np.sum(self.rgb, axis=0)

    def __str__(self):
        return "count: " + str(self.count) + " integers: " + str(self.rgb[1].tolist())+ " floats: " + str(self.rgb[0].tolist())

    def __repr__(self):
        return "CumulativePixel(rgb = " + str(tuple(np.sum(self.rgb, axis=0))) + ", count=" + str(self.count) +")"

修改 我创建了这个类的实例(在另一个类中),如下所示:

self.pixeldata = [CumulativePixel() for i in range(self.imagewidth*self.imageheight)]

1 个答案:

答案 0 :(得分:1)

这是一个常见的错误,最常见的情况是使用列表作为函数的默认值。

pdf()

初始化类时,会创建一次此数组。因此,所有实例共享相同的count=np.array([0.0, 0.0, 0.0]) 属性,相同的数组。他们没有得到新的阵容。

执行create时,您可以就地修改它。

使用self.create +=...,您可以创建一个新数组,因此一个实例中的更改不会影响其他实例。

做这样的事情是个好习惯:

self.create = self.create + ...

现在,默认值将是新鲜的,每个实例都是唯一的。