11

I am subclassing Numpy's ndarray class, adding some meta-data and additional methods. I'm trying to follow the instructions in this article and that one. However, some Numpy (or Scipy) functions return the base class "ndarray" instead of my custom subclass. Other Numpy functions DO return my subclass, and I don't know what's the reason for the difference. How can I make all the numpy/scipy functions return my subclass? here's what I did:

class Signal(np.ndarray):
    def __new__(cls, filename):
        #print "In __new__" #TEMP DEBUG
        ret = np.fromfile(filename, dtype = np.int32)
        ret = ret.view(cls) # convert to my class, i.e. Signal
        ret.parse_filename(filename)
        return ret

    def __array_finalize__(self, obj):
        #print "in __array_finalize__" #TEMP DEBUG
        if obj is None: return # shouldn't actually happen.
        # copy meta-fields from source, if it has them (otherwise put None's)
        self.filename = getattr(obj, "filename", None)
        self.folder = getattr(obj, "folder", None)
        self.label = getattr(obj, "label", None)
        self.date = getattr(obj, "date", None)
        self.time = getattr(obj, "time", None)
        #etc

here are some usage examples:

these work as expected -

>>> s = Signal(filename)
>>> s2 = s[10:20]
>>> type (s2)
<class '__main__.Signal'>
>>> s3 = s + 17
>>> type (s3)
<class '__main__.Signal'>
>>> s4 = np.sqrt(s)
>>> type(s4)
<class '__main__.Signal'>

however, what about these?

>>> s5 = log10(s)
>>> type(s5)
<type 'numpy.ndarray'>
>>> s6 = np.fft.fft(s)
>>> type(s6)
<type 'numpy.ndarray'>

looking into the code of fft and log10 I can see that they use asarray(), which strips the subclass and returns an ndarray, explaining the behavior. Therefore, my question isn't "why, technically, this happens" but more a design question - how should I write my code so this doesn't happen?

p.s. I'm a newbie both at Python and here on Stack Overflow, so please excuse any obvious mistakes or inappropriateness...

thanks, Guy.

tinkerer
  • 153
  • 7

1 Answers1

1

I am not sure about fft, but np.log10 is a ufunc. The following page explains how the output type of a ufunc is determined: http://docs.scipy.org/doc/numpy/reference/ufuncs.html#output-type-determination

It wouldn't surprise me if fft always returned an ndarray though (I haven't looked at the source code, but the FFT clearly doesn't fit the definition of a ufunc). If that's the case, you can always write your own wrapper and call that instead.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    To expand on this, you need to implement the `__array_wrap__` method in your subclass. See http://docs.scipy.org/doc/numpy/user/basics.subclassing.html#array-wrap-for-ufuncs . – Stephen Terry May 31 '11 at 17:46
  • ok, I just discovered that there's a difference between Numpy's `log10()` and Scipy's `log10()`... the numpy one is well behaved ufunc, returning my subclass as implemented above (without `__array_wrap__` by the way). The scipy `log10` returns a base class though. anyone knows what's the rationale behind this? which log10 should I use...? any difference in actual numerical output? how about other functions? what's the reason for the duplicates anyway...? – tinkerer Jun 01 '11 at 11:52
  • Stephen, can you elaborate on why do I need to implement `__array_wrap__`, now that I notice that numpy functions actually DO return my subclass, only Scipy's don't (see my comment above)? will it help with Scipy's functions? any problem with what I did in my code above, considering that I didn't implement `__array_wrap__`? – tinkerer Jun 01 '11 at 11:55
  • 1
    @tinkerer: I've been wondering about the apparent duplication between numpy and scipy myself. I've just posted a question about this: http://stackoverflow.com/questions/6200910/relationship-between-scipy-and-numpy – NPE Jun 01 '11 at 12:15