Let's look at some very simple behaviour of numpy arrays:
import numpy as np
arr = np.array([1,2,3,4,5])
max_value = arr.max() # returns 5
Now I create a class which inherits from np.ndarray:
class CustomArray(np.ndarray):
def __new__(cls, *args, **kwargs):
obj = np.array(*args, **kwargs).view(cls)
return obj
new_arr = CustomArray([1,2,3,4,5])
I haven't actually changed any behaviour - I just made a nominal change in what class the object is.
And yet:
new_max_value = new_arr.max() # returns CustomArray(5)
The return value is an CustomArray instance? Why? arr.max() didn't return a np.ndarray instance, just a plain numpy integer.
Similarly, why do both arr == new_arr and new_arr == arr return CustomArray instances? Shouldn't the former call arr.__eq__(new_arr), which should return a np.ndarray instance?
EDIT:
Note that I override the __new__ method for the sake of easy constructors. E.g. the equivalent of np.array([1,2,3,4,5]) can just be CustomArray([1,2,3,4,5]), whereas if I plainly inherit from np.ndarray I'd have to do something like new_arr = CustomArray((5,)); new_arr[:] = np.array([1,2,3,4,5]).
matrixandmasked arrayhandle this issue. Many methods/functions make sure the return value has the same subclass as the inputs. Note themax(axis=...)should be some sort of array. It's the scalar case the requires special handling.