为什么更改 numpy 子类的属性不会更改子类数组?
Why changes on attributes at a numpy subclass does not change the subclass array?
我在子类化 numpy 数组时遇到以下问题
例如:
import numpy
class Example(numpy.ndarray):
def __new__(cls, x, y):
dt = [('x', 'float'), ('y', 'float')]
buffer = numpy.array(zip(x, y),dtype=dt)
obj = super(Example, cls).__new__(cls, buffer.shape, dtype=dt,
buffer=buffer)
obj.x = numpy.array(x, dtype='float')
obj.y = numpy.array(y, dtype='float')
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.x = getattr(obj, 'x', None)
self.y = getattr(obj, 'y', None)
如果我用 obj.x 和 obj['x'] 进行操作,一个不会改变另一个。例如这些操作将显示不同的结果
x = [1,2,3,4]
y = [1,1,1,1]
obj = Example(x,y)
obj.x = obj.x / 2.
print obj.x, obj['x']
或
obj = Example(x,y)
obj['x'] = obj['x'] / 2.
print obj.x, obj['x']
当我对其中一个(obj.x 或 obj['x'] 进行操作时,如何才能使另一个也发生变化?
使用 [('x', 'float'), ('y', 'float')]
作为数据类型告诉 numpy 创建一个 structured array 字段名为 x
和 y
。
正如您所展示的,这些是使用括号访问的。
现在您还向 class 添加了属性(使用 obj.<name>
访问)。
但是,您已经为属性创建了新数组。
要修复属性符号,您需要让 x
和 y
属性通过这些名称指向数组字段,而不是单独的数组。
所以改变
obj.x = numpy.array(x, dtype='float')
obj.y = numpy.array(y, dtype='float')
到
obj.x = obj['x']
obj.y = obj['y']
edit 这仅修复了问题中的第二个测试用例。分配给 x
或 y
仍然会分配一个新对象作为属性,而不是更新 x
或 y
。
要解决此问题,需要修改 class 的 __setattr__
方法(参见 here)
def __setattr__(self, attr, value):
if attr in ['x', 'y']:
getattr(self, attr)[:] = attr
else:
setattr(self, attr, value)
但是,Numpy 已经有一个数组类型来允许访问字段作为属性。
你可以这样使用它
obj = np.array(np.r_[x, y], dtype=[('x', 'float'), ('y', 'float')])
obj = obj.view(np.recarray)
恭喜你!您已经有效地重新实现了 record arrays(好吧,np.recarray
将不允许访问与 ndarray
具有的属性或函数匹配的字段名称。所以像 mean
或 [=28 这样的名称=] 出来了,而你的代码将允许这些)。
当您花费数小时创建 numpy 已经拥有的东西时,这总是一个好兆头(而且非常令人沮丧)。
我在子类化 numpy 数组时遇到以下问题
例如:
import numpy
class Example(numpy.ndarray):
def __new__(cls, x, y):
dt = [('x', 'float'), ('y', 'float')]
buffer = numpy.array(zip(x, y),dtype=dt)
obj = super(Example, cls).__new__(cls, buffer.shape, dtype=dt,
buffer=buffer)
obj.x = numpy.array(x, dtype='float')
obj.y = numpy.array(y, dtype='float')
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.x = getattr(obj, 'x', None)
self.y = getattr(obj, 'y', None)
如果我用 obj.x 和 obj['x'] 进行操作,一个不会改变另一个。例如这些操作将显示不同的结果
x = [1,2,3,4]
y = [1,1,1,1]
obj = Example(x,y)
obj.x = obj.x / 2.
print obj.x, obj['x']
或
obj = Example(x,y)
obj['x'] = obj['x'] / 2.
print obj.x, obj['x']
当我对其中一个(obj.x 或 obj['x'] 进行操作时,如何才能使另一个也发生变化?
使用 [('x', 'float'), ('y', 'float')]
作为数据类型告诉 numpy 创建一个 structured array 字段名为 x
和 y
。
正如您所展示的,这些是使用括号访问的。
现在您还向 class 添加了属性(使用 obj.<name>
访问)。
但是,您已经为属性创建了新数组。
要修复属性符号,您需要让 x
和 y
属性通过这些名称指向数组字段,而不是单独的数组。
所以改变
obj.x = numpy.array(x, dtype='float')
obj.y = numpy.array(y, dtype='float')
到
obj.x = obj['x']
obj.y = obj['y']
edit 这仅修复了问题中的第二个测试用例。分配给 x
或 y
仍然会分配一个新对象作为属性,而不是更新 x
或 y
。
要解决此问题,需要修改 class 的 __setattr__
方法(参见 here)
def __setattr__(self, attr, value):
if attr in ['x', 'y']:
getattr(self, attr)[:] = attr
else:
setattr(self, attr, value)
但是,Numpy 已经有一个数组类型来允许访问字段作为属性。 你可以这样使用它
obj = np.array(np.r_[x, y], dtype=[('x', 'float'), ('y', 'float')])
obj = obj.view(np.recarray)
恭喜你!您已经有效地重新实现了 record arrays(好吧,np.recarray
将不允许访问与 ndarray
具有的属性或函数匹配的字段名称。所以像 mean
或 [=28 这样的名称=] 出来了,而你的代码将允许这些)。
当您花费数小时创建 numpy 已经拥有的东西时,这总是一个好兆头(而且非常令人沮丧)。