6

I'm trying to subclass numpy's ndarray class, and have had some luck. The behavior that I would like is nearly exactly the same as the example given in the documentation. I want to add a parameter name to the array (which I use to keep track of where the data originally came from).

class Template(np.ndarray):
    """A subclass of numpy's n dimensional array that allows for a
    reference back to the name of the template it came from.
    """
    def __new__(cls, input_array, name=None):
        obj = np.asarray(input_array).view(cls)
        obj.name = name
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.name = getattr(obj, 'name', None)

This works, except that, like this question, I want any transformation involving my subclass to return another instance of my subclass.

Sometimes numpy functions do return an instance of Template:

>>> a = Template(np.array([[1,2,3], [2,4,6]], name='from here')
>>> np.dot(a, np.array([[1,0,0],[0,1,0],[0,0,1]]))
Template([[1, 2, 3],
       [2, 4, 6]])

However, sometimes they don't:

>>> np.dot(np.array([[1,0],[0,1]]), a)
array([[1, 2, 3],
       [2, 4, 6]])

In the question I linked to above, it was suggested that the OP should override the __wrap_array__ method for the subclass. However, I don't see any justification in this. In some situations, I'm getting my expected behavior with the default __array_wrap__. The docs seem to suggest that I'm running into a situation where it's the other argument's __array_wrap__ method being called because of a higher __array_priority__ value:

Note that the ufunc (np.add) has called the __array_wrap__ method of the input with the highest __array_priority__ value

So my question has a couple related parts. First: can I set the __array_priority__ attribute of my subclass such that its __array_wrap__ will always be called? Second: Is this the best/easiest way to go about achieving my desired behavior?

Community
  • 1
  • 1
Wilduck
  • 13,822
  • 10
  • 58
  • 90

1 Answers1

0

When two objects have the same __array_priority__:

>>> np.array([[1,0],[0,1]]).__array_priority__
0.0
>>> a.__array_priority__
0.0

And only one object's methods can be used, the tie is resolved by using the first array's/object's methods. (In your case __array_wrap__)

From the question it seems like your class' methods should always be preferred, since they are the same (through inheritance) or overridden.

So I would just crank up the __array_priority__.

class Template(np.ndarray):
    __array_priority__ = 1.0 (Or whichever value is high enough)
    ...

After you do this no matter where the template object is in a calculation. It's methods will be preferred over standard arrays' methods.

cchristelis
  • 1,985
  • 1
  • 13
  • 17