I have a problem. Problem is: I want to create a subclass of numpy array, and then make an array of objects of that type. When I reference an item in that array, I want it still to be an instance of that subclass. Instead, it is an instance of numpy array.
Here is a test that fails:
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
Gives me: AttributeError: 'numpy.ndarray' object has no attribute 'n_colours'
How can I make this work?
Things tried already:
- Setting subok=True when constructing the video - this only works when constructing an array from a single instance of the subclass object, not a list.
- Setting dtype=object or dtype=ImageWrapper doesn't work
I recognize that I could just make video a list, but it would be preferable to keep it as a numpy array for other reasons.
arrayon a list of 3D arrays, you get a 4D array, not a 1D array full of 3D arrays. Obviously that 4D array can't be anImageWrapper, so it's anndarray, so any slice of it is anndarrayas well, no matter where the data originally came from. The question is, why do you want it to be an array? A 1D array ofobjectdoesn't lose all of the benefits of numpy over native lists, but it loses a lot of them, and if you can tell us the "other reasons" in your last sentence, it might help.ImageWrapper? Yourn_colourswould have to return an array of N-3 dimensions instead of a scalar if N>3 (or just raise an exception), but otherwise, what would be the problem? Because that would make things a lot simpler…n_coloursandcropanddownsampleand so on over that array. A 4D array gives you all of that for free (at least on the caller side; you have to be careful on the implementation side, as Bi Rico shows); with an array of objects that are arrays, you have to manually wrap the unbound method in aufuncto do anything. (Unless you're planning to just iterate the objects, in which case, why use an array?)