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
.