2017-12-02 4 views
0

Linux에서 python 3.6 및 numpy 1.12.1을 사용할 때 이상한 동작이 발생했습니다.이 numpy 속성이 인스턴스간에 갑자기 공유되는 이유

나는 np.array([0.0, 0.0, 0.0])으로 초기화하는 self.count 속성을 가지고 있습니다. 나는 self.count이 다른 속성처럼 행동하고 클래스 인스턴스 당 자체 값을 가질 것이라고 기대합니다.

그러나, addPixel 방법에 아래의 코드에 나는

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

self.count 속성이 클래스 CumulativePixel의 모든 인스턴스 증가됩니다를 사용하는 경우. 왜 이런 일이 일어나고 내가 할 때 문제가 해결되는 이유를 알고 싶습니다.

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

이 공통의 버그가 가장 자주 볼 수있다 값.

count=np.array([0.0, 0.0, 0.0]) 

이 배열은 클래스가 초기화 될 때 한 번 만들어집니다. 따라서 모든 인스턴스는 동일한 create 속성을 공유합니다. 그들은 새로운 배열을 얻지 못합니다.

self.create +=...을 변경하면 내부 수정됩니다.

self.create = self.create + ...으로 새 배열을 만들면 한 인스턴스의 변경 사항이 다른 인스턴스에 영향을주지 않습니다.

def __init__(self, create=None): 
    if create is None: 
     create = np.array([1,2,3,4]) 
    self.create = create 

지금 기본값은 각 인스턴스에 대해 고유 한 신선한 것 :

이 같은 것을 할 수있는 좋은 방법입니다.

+0

내부 기본값이 사실 특정 값일지라도 많은 라이브러리가 기본값으로 None을 사용하는 이유가 여기 있습니다. 또한 동일한 포인터의 여러 복사본으로 끝나는 목록 곱셈 ([object] * number)을 생각 나게합니다. – evolution

관련 문제