为什么对 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 创建一个结构化数组,其中包含名为xy的字段。 如您所显示的,可以使用括号访问这些内容。 现在,您还向类添加了属性(使用obj.<name>访问(。 但是,您已为属性创建了新数组。 要修复属性表示法,您需要让xy属性通过这些名称指向数组字段,而不是单独的数组。 所以改变

obj.x = numpy.array(x, dtype='float')
obj.y = numpy.array(y, dtype='float')

obj.x = obj['x']
obj.y = obj['y']

编辑这只会修复问题中的第二个测试用例。 分配给xy仍会分配一个新对象作为属性,而不是更新xy。 要解决此问题,有必要修改类的__setattr__方法(请参阅此处(

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)  

所以恭喜你!您已经有效地重新实现了记录数组(好吧,np.recarray不允许访问与ndarray具有的属性或函数匹配的字段名称。 所以像meanndim这样的名称已经出来了,而你的代码会允许这些(。 当你花几个小时创造一些已经有的东西时,这总是一个好兆头(而且非常令人沮丧(。

最新更新