子类化numpy.ma.MaskedArray
我正在尝试对numpy的 MaskedArray
进行子类化,想要添加一个属性,但似乎没有得到预期的结果。
一开始我是按照 这个例子 来子类化 numpy.ndarray
的,那个例子运行得很好。
然后我尝试对 numpy.ma.MaskedArray
进行子类化,代码如下:
import numpy as np
class MyMaskedArray(np.ma.MaskedArray):
def __new__(cls, input_array, info=None):
obj = np.asarray(input_array).view(cls)
obj.info = info
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.info = getattr(obj, 'info', None)
super(MyMaskedArray, self).__array_finalize__(obj)
arr = np.arange(5)
obj = MyMaskedArray(arr, info='information')
print obj.info
print obj[1:].info
结果是
information
None
我本来期待能看到“information”出现两次。
把这一行 obj = np.asarray(input_array).view(cls)
替换成 obj = np.ma.MaskedArray(input_array).view(cls)
或者 obj = np.ma.MaskedArray.__new__(cls, input_array)
并没有解决这个问题(我这么做是因为我想在将来的子类中传递 *args
和 **kwargs
给 __new__
)。
需要注意的是,我还必须在我子类的 __array_finalize__
中调用 MaskedArray.__array_finalize
,这和 ndarray
子类的例子不同;如果不这样做,_mask
属性就找不到了。
也许有人能帮我解答:
如何让
obj[1:].info
保持原来的obj.info
为什么
ndarray
不需要在__array_finalize__
中调用父类,而MaskedArray
需要(这算是个额外的问题)。
我想对子类 MaskedArray
,而不是写一个容器类,因为后者会失去一些 MaskedArray
带来的便利。
(注意:这和 这个问题 不一样,因为我已经“解决”了 __init__
/ __new__
的问题。)
1 个回答
为了让你的切片功能正常工作,你可能需要重写一下 __getitem__
方法:
def __getitem__(self, item):
out = np.ma.MaskedArray.__getitem__(self, item)
out.info = self.info
return out
同样的道理适用于 __setitem__
方法。
如果你的 info
属性比较简单,比如你举的例子,你可以看看 MaskedArray
的 _optinfo
属性,它就是为这个目的设计的:它其实就是一个字典,用来存储一些必须保留的信息。下面是一个例子:
class MyMaskedArray(np.ma.MaskedArray):
def __new__(cls, input_array, info=None):
obj = np.asarray(input_array).view(cls)
obj._optinfo['info'] = info
return obj
@property
def info(self):
return self._optinfo.get('info', None)
注意这里的 .info
是一个只读属性,但其实很简单就可以让它变成可写的。
关于 __array_finalize__
我不太明白你的问题:ndarray
本身就是一个父类。MaskedArray
是 ndarray
的子类,因此需要定义一个 __array_finalize__
方法,特别是用来设置掩码(通过 _mask
参数)。想了解更多关于子类的信息,可以查看这个 链接。
在你的例子中,你使用自己的 __array_finalize__
来设置 .info
属性。在这种情况下,你确实需要调用父类的方法 MaskedArray.__array_finalize__
,这是基本的 Python 子类规则。注意,如果你选择使用 _optinfo
的方式,就不需要明确地定义 __array_finalize__
了……
注意
__array_prepare__
和__array_wrap__
方法实际上是用来在对ndarray
子类实例应用函数之前准备它,以及处理函数结果的。