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)]
これは、内部デフォルト値が実際には特定の値であることが多いにもかかわらず、多くのライブラリがデフォルトとしてNoneを使用する理由と考えられます。また、同じポインタの複数のコピーで終わるリストの乗算([object] * number)を思い出させます。 – evolution