How to subclass a subclass of numpy.ndarray

I am trying to subclass my own subclass of numpy.ndarray. I really donโ€™t understand what the problem is, and I would like someone to explain what is wrong in the following cases, and how to do what I am trying to do.

What I'm trying to achieve:

I have a subclass of numpy.ndarry that behaves the way I want (class A in the code below). I want to subclass A (class B in the code below), so B contains additional information (name) and methods (decorated method .simple_data).

Case 1:

import numpy as np class A(np.ndarray): def __new__(cls,data): obj = np.asarray(data).view(cls) return obj def __array_finalize(self,obj): if obj is None: return class B(A): def __init__(self,data,name): super(B,self).__init__(data) self.name = name @property def simple_data(self): return [data[0,:],data[:,0]] if __name__ == '__main__': data = np.arange(20).reshape((4,5)) b = B(data,'B') print type(b) print b.simple_data 

Running this code outputs the result:

 Traceback (most recent call last): File "ndsubclass.py", line 24, in <module> b = B(data,'B') TypeError: __new__() takes exactly 2 arguments (3 given) 

I assume that this is due to the variable "name" in construct B and that because A is a subclass of numpy.array, A new method is called before B init . Thus, to fix this, I assume that B also needs a new method that handles the additional argument accordingly.

My guess is like:

 def __new__(cls,data,name): obj = A(data) obj.name = name return obj 

should do this, but how to change the obj class?

Case 2:

 import numpy as np class A(np.ndarray): def __new__(cls,data): obj = np.asarray(data).view(cls) return obj def __array_finalize__(self,obj): if obj is None: return class B(A): def __new__(cls,data): obj = A(data) obj.view(cls) return obj def __array_finalize__(self,obj): if obj is None: return @property def simple_data(self): return [self[0,:],self[:,0]] if __name__ == '__main__': data = np.arange(20).reshape((4,5)) b = B(data) print type(b) print b.simple_data() 

At startup, the output:

 <class '__main__.A'> Traceback (most recent call last): File "ndsubclass.py", line 30, in <module> print b.simple_data() AttributeError: 'A' object has no attribute 'simple_data' 

This surprises me as I expected:

 <class '__main__.B'> [array([0, 1, 2, 3, 4]), array([ 0, 5, 10, 15])] 

I assume that calling view () in B. new () incorrectly defines the obj class. Why?

I am confused about what is happening and would be very grateful if anyone could explain this.

+6
source share
1 answer

For Case 1, the easiest way:

 class B(A): def __new__(cls,data,name): obj = A.__new__(cls, data) obj.name = name return obj 

__new__ is actually a static method that takes a class as the first argument, not a class method, so you can call it directly with the class you want to create.

For case 2 , view does not work in place, you need to assign the result to something, the easiest way:

 class B(A): def __new__(cls,data): obj = A(data) return obj.view(cls) 

Also, you have __array_finalize__ defined the same thing in A and B there (maybe just a typo) - you don't need to do this.

+4
source

Source: https://habr.com/ru/post/896840/


All Articles