Subclass of numpy ndarray doesn't work as expected
numpy, python
Solution
`np.sum` can accept a variety of objects as input: not only ndarrays, but also lists, generators, `np.matrix`s, for instance. The `keepdims` parameter obviously does not make sense for lists or generators. It is also not appropriate for `np.matrix` instances either, since `np.matrix`s always have 2 dimensions. If you look at the call signature for `np.matrix.sum` you see that its `sum` method has no `keepdims` parameter:
Definition: np.matrix.sum(self, axis=None, dtype=None, out=None)
So some subclasses of `ndarray` may have `sum` methods which do not have a `keepdims` parameter. This is an unfortunate violation of the Liskov substitution principle and the origin of the pitfall you encountered.
Now if you look at the source code for `np.sum`, you see that it is a delegating function which tries to determine what to do based on the type of the first argument.
If the type of the first argument is not `ndarray`, it drops the `keepdims` parameter. It does this because passing the keepdims parameter to `np.matrix.sum` would raise an exception.
So because `np.sum` is trying to do the delegation in the most general way, not making any assumption about what arguments a subclass of ndarray may take, it drops the `keepdims` parameter when passed a `fooarray`.
The workaround is to not use `np.sum`, but call `a.sum` instead. This is more direct anyway, since `np.sum` is merely a delegating function.
import numpy as np
class fooarray(np.ndarray):
def __new__(cls, input_array, *args, **kwargs):
obj = np.asarray(input_array, *args, **kwargs).view(cls)
return obj
a = fooarray(np.random.randn(3, 5))
b = np.random.randn(3, 5)
a_sum = a.sum(axis=0, keepdims=True)
b_sum = np.sum(b, axis=0, keepdims=True)
print(a_sum.ndim) # 2
print(b_sum.ndim) # 2
Problem
`Hello, everyone. I found there is a strange behavior when subclassing a ndarray. ``` import numpy as np class fooarray(np.ndarray): def __new__(cls, input_array, *args, **kwargs): obj = np.asarray(input_array).view(cls) return obj def __init__(self, *args, **kwargs): return def __array_finalize__(self, obj): return a=fooarray(np.random.randn(3,5)) b=np.random.randn(3,5) a_sum=np.sum(a,axis=0,keepdims=True) b_sum=np.sum(b,axis=0, keepdims=True) print a_sum.ndim #1 print b_sum.ndim #2 ``` As you have seen, the `keepdims` argument doesn't work for my subclass `fooarray`. It lost one of its axis. How can't I avoid this problem? Or more generally, how can I subclass numpy ndarray correctly?