acdr
acdr

Reputation: 4706

Why do methods of classes that inherit from numpy arrays return different things?

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]).

Upvotes: 5

Views: 724

Answers (1)

Josh L.
Josh L.

Reputation: 46

Following the numpy docs: array_wrap gets called at the end of numpy ufuncs and other numpy functions, to allow a subclass to set the type of the return value and update attributes and metadata.

class CustomArray(np.ndarray):
    def __new__(cls, a, dtype=None, order=None):
        obj = np.asarray(a, dtype, order).view(cls)
        return obj

    def __array_wrap__(self, out_arr, context=None):
        return np.ndarray.__array_wrap__(self, out_arr, context)

c = CustomArray([1,2,3,4])
c.max() # returns 4

Upvotes: 3

Related Questions