为什么这个 numpy 属性突然在实例之间共享
Why does this numpy attribute suddenly become shared between instances
我在 Linux 下使用 python 3.6 和 numpy 1.12.1 时偶然发现了奇怪的行为。
我有一个属性 self.count
,我用 np.array([0.0, 0.0, 0.0])
对其进行了初始化。我希望 self.count
的行为与任何其他属性一样,并且每个 class 实例都有自己的值。
然而,在下面的代码中,在 addPixel
方法中,当我使用
self.count += (1.0, 1.0, 1.0)
self.count 属性在 class 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) +")"
编辑:
我创建了这个 class 的实例(在另一个 class 中)如下:
self.pixeldata = [CumulativePixel() for i in range(self.imagewidth*self.imageheight)]
这是一个常见错误,在使用列表作为函数的默认值时最常见。
count=np.array([0.0, 0.0, 0.0])
这个数组在class初始化时创建一次。所以所有实例共享相同的 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
现在默认值将是最新的,每个实例都是唯一的。
我在 Linux 下使用 python 3.6 和 numpy 1.12.1 时偶然发现了奇怪的行为。
我有一个属性 self.count
,我用 np.array([0.0, 0.0, 0.0])
对其进行了初始化。我希望 self.count
的行为与任何其他属性一样,并且每个 class 实例都有自己的值。
然而,在下面的代码中,在 addPixel
方法中,当我使用
self.count += (1.0, 1.0, 1.0)
self.count 属性在 class 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) +")"
编辑: 我创建了这个 class 的实例(在另一个 class 中)如下:
self.pixeldata = [CumulativePixel() for i in range(self.imagewidth*self.imageheight)]
这是一个常见错误,在使用列表作为函数的默认值时最常见。
count=np.array([0.0, 0.0, 0.0])
这个数组在class初始化时创建一次。所以所有实例共享相同的 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
现在默认值将是最新的,每个实例都是唯一的。