Subclassing numpy ndarray problem

后端 未结 3 2088
清酒与你
清酒与你 2020-12-06 02:40

I would like to subclass numpy ndarray. However, I cannot change the array. Why self = ... does not change the array? Thanks.

import numpy as np         


        
相关标签:
3条回答
  • 2020-12-06 02:49

    Perhaps make this a function, rather than a method:

    import numpy as np
    
    def remove_row(arr,col,val):
        return arr[arr[col]!=val]
    
    z = np.array([(1,2,3), (4,5,6), (7,8,9)],
        dtype=[('a', int), ('b', int), ('c', int)])
    
    z=remove_row(z,'a',4)
    print(repr(z))
    
    # array([(1, 2, 3), (7, 8, 9)], 
    #       dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<i4')])
    

    Or, if you want it as a method,

    import numpy as np
    
    class Data(np.ndarray):
    
        def __new__(cls, inputarr):
            obj = np.asarray(inputarr).view(cls)
            return obj
    
        def remove_some(self, col, val):
            return self[self[col] != val]
    
    z = np.array([(1,2,3), (4,5,6), (7,8,9)],
        dtype=[('a', int), ('b', int), ('c', int)])
    d = Data(z)
    d = d.remove_some('a', 4)
    print(d)
    

    The key difference here is that remove_some does not try to modify self, it merely returns a new instance of Data.

    0 讨论(0)
  • 2020-12-06 02:51

    I tried to do the same, but it is really very complex to subclass ndarray.

    If you only have to add some functionality, I would suggest to create a class which stores the array as attribute.

    class Data(object):
    
        def __init__(self, array):
            self.array = array
    
        def remove_some(self, t):
            //operate on self.array
            pass
    
    d = Data(z)
    print(d.array)
    
    0 讨论(0)
  • 2020-12-06 03:06

    The reason you are not getting the result you expect is because you are re-assigning self within the method remove_some. You are just creating a new local variable self. If your array shape were not to change, you could simply do self[:] = ... and you could keep the reference to self and all would be well, but you are trying to change the shape of self. Which means we need to re-allocate some new memory and change where we point when we refer to self.

    I don't know how to do this. I thought it could be achieved by __array_finalize__ or __array__ or __array_wrap__. But everything I've tried is falling short.

    Now, there's another way to go about this that doesn't subclass ndarray. You can make a new class that keeps an attribute that is an ndarray and then override all the usual __add__, __mul__, etc.. Something like this:

    Class Data(object):
        def __init__(self, inarr):
            self._array = np.array(inarr)
        def remove_some(x):
            self._array = self._array[x]
        def __add__(self, other):
            return np.add(self._array, other)
    

    Well, you get the picture. It's a pain to override all the operators, but in the long run, I think more flexible.

    You'll have to read this thoroughly to do it right. There are methods like __array_finalize__ that need to be called a the right time to do "cleanup".

    0 讨论(0)
提交回复
热议问题