创建一个numpy数组子类,使所有形状更改操作返回普通数组

8 投票
1 回答
1142 浏览
提问于 2025-04-16 14:39

我有一个数组的子类,其中一些额外的属性只对对象的原始形状有效。有没有办法确保所有改变数组形状的操作都返回一个普通的 numpy 数组,而不是我这个类的实例呢?

我已经写了 `array_wrap`,但这似乎对像 np.meannp.sumnp.rollaxis 这样的操作没有任何影响。这些操作都只是返回了我这个类的实例。

import numpy as np    

class NewArrayClass(np.ndarray):
    __array_priority__ = 3.0
    def __array_wrap__(self, out_arr, context=None):
        if out_arr.shape == self.shape:
            out = out_arr.view(new_array)
            # Do a bunch of class dependant initialization and attribute copying.
            # ...
            return out
        else:
            return np.asarray(out_arr)

A = np.arange(10)
A.shape = (5, 2)
A = arr.view(NewArrayClass)
# Would like this to be np.ndarray, but get new_array_class.
print type(np.sum(A, 0))

我想我需要在 __new____array_finalize__ 中做些什么,但我完全不知道该怎么做。

更新: 在仔细阅读了 numpy 关于子类化的文档后(http://docs.scipy.org/doc/numpy/user/basics.subclassing.html),我发现所有改变数组形状的操作都在执行“从模板新建”的操作。所以问题变成了,如何让“从模板新建”的操作返回 ndarray 实例,而不是我这个类的实例。根据我所了解,__new__ 在这些函数中从未被调用。

替代方案: 假设上面的事情不可能实现,我至少如何在 __array_finalize__ 中识别出“从模板新建”的操作(与视图转换不同)?这至少可以让我解除一些通过引用复制的属性。我也可以设置一个标志,告诉新实例它的形状是无效的。

1 个回答

1

如果你在你的 NewArrayClass 实例中没有添加任何新的成员,你可以重新指定返回实例的 __class__ 属性。

A.__class__ = np.ndarray

关键是,为什么你想这么做呢?你在其他地方会进行严格的类型检查吗?其实用“鸭子类型”会更有效。

撰写回答