【发布时间】:2014-07-22 23:03:13
【问题描述】:
我有问题。问题是:我想创建一个 numpy 数组的子类,然后创建一个该类型的对象数组。当我引用该数组中的一个项目时,我希望它仍然是该子类的一个实例。相反,它是一个 numpy 数组的实例。
这是一个失败的测试:
import numpy as np
class ImageWrapper(np.ndarray):
def __new__(cls, image_data):
assert image_data.ndim in (2, 3)
return image_data.view(cls)
@property
def n_colours(self):
return 1 if self.ndim==2 else self.shape[2]
n_frames = 10
frames = [ImageWrapper(np.random.randint(255, size = (20, 15, 3)).astype('uint8')) for _ in xrange(n_frames)]
video = np.array(frames)
assert video[0].n_colours == 3
给我:AttributeError: 'numpy.ndarray' 对象没有属性 'n_colours'
我怎样才能做到这一点?
已经尝试过的事情:
- 在构造视频时设置 subok=True - 这仅适用于从子类对象的单个实例而不是列表构造数组时。
- 设置 dtype=object 或 dtype=ImageWrapper 不起作用
我知道我可以将视频制作成一个列表,但出于其他原因,最好将其保留为 numpy 数组。
【问题讨论】:
-
问题是当您在 3D 数组列表上调用
array时,您会得到一个 4D 数组,而不是一个充满 3D 数组的 1D 数组。显然,这个 4D 数组不可能是ImageWrapper,所以它是ndarray,所以它的任何切片也是ndarray,无论数据最初来自哪里。问题是,为什么你希望它是一个数组?object的一维数组并没有失去 numpy 优于原生列表的 所有 优点,但它失去了 很多 它们,如果你能告诉我们最后一句中的“其他原因”,它可能会有所帮助。 -
另外,您的设计是否有理由要求 4D 数组不能成为
ImageWrapper?如果 N>3(或只是引发异常),您的n_colours将不得不返回一个 N-3 维数组而不是一个标量,否则,会有什么问题?因为那会让事情变得简单得多…… -
“其他原因”不是一个很好的原因,只是这是接口的一部分,其中数组是预期的数据类型。在这种情况下,Jaime 建议的对象数组就可以了。
-
但是 4D 数组子类也不能工作吗?在我看来,如果您的代码需要一个数组,它会想要在该数组上广播
n_colours和crop和downsample等等。 4D 数组免费为您提供所有这些(至少在调用方;您必须在实现方面小心,如 Bi Rico 所示);对于数组对象数组,您必须手动将未绑定的方法包装在ufunc中才能执行任何操作。 (除非您打算只迭代对象,在这种情况下,为什么要使用数组?)
标签: python arrays numpy subclassing multidimensional-array