When subclassing a numpy ndarray, how can I modify __getitem__ properly? When subclassing a numpy ndarray, how can I modify __getitem__ properly? numpy numpy

When subclassing a numpy ndarray, how can I modify __getitem__ properly?


I had a similar problem that I solved using the numpy matrix class as an example. __getitem__ can be called multiple times as you have noticed before the array gets created in __array_finalize__. So the solution is to store the potential new index in __getitem__ but set it in __array_finalize__.

class MyClass(np.ndarray):    def __new__(cls, data, time=None):        obj = np.asarray(data).view(cls)        obj.time = time        return obj    def __array_finalize__(self, obj):        setattr(self, 'time', obj.time)        try:            self.time = self.time[obj._new_time_index]        except:            pass    def __getitem__(self, item):        try:            if isinstance(item, (slice, int)):                self._new_time_index = item            else:                self._new_time_index = item[0]        except:             pass        return super().__getitem__(item)


As you want to update time on slices, try

if isinstance(item, slice):    ret.time = self.time.__getitem__(item)

in your __getitem__ method.

Then your time-adjusting code is only called once per slicing and never executed when getting a single item from your array.


The way I solved my issue (which was trying to do something very similar) was the following:

class MyClass(np.ndarray):    ...    def __getitem__(self, item):        #print item #for testing        ret = super(MyClass, self).__getitem__(item)        if not isinstance(self, MyClass):            return ret        ret.time = self.time.__getitem__(item)        return ret

This way, if __getitem__ gets called multiple times, you will only adjust the time method on the first call where the calling instance is MyClass.