[Numpy-discussion] numpy.trapz() doesn't respect subclass

Darren Dale dsdale24@gmail....
Sun Mar 28 02:29:30 CDT 2010


On Sat, Mar 27, 2010 at 10:23 PM,  <josef.pktd@gmail.com> wrote:
> subclasses of ndarray, like masked_arrays and quantities, and classes
> that delegate to array calculations, like pandas, can redefine
> anything. So there is not much that can be relied on if any subclass
> is allowed to be used inside a function
>
> e.g. quantities redefines sin, cos,...
> http://packages.python.org/quantities/user/issues.html#umath-functions

Those functions were only intended to be used in the short term, until
the ufuncs that ship with numpy included a mechanism that allowed
quantity arrays to propagate the units. It would be nice to have a
mechanism (like we have discussed briefly just recently on this list)
where there is a single entry point to a given function like add, but
subclasses can tweak the execution.

We discussed the possibility of simplifying the wrapping scheme with a
method like __handle_gfunc__. (I don't think this necessarily has to
be limited to ufuncs.) I think a second method like __prepare_input__
is also necessary. Imagine something like:

class GenericFunction:
    @property
    def executable(self):
        return self._executable
    def __init__(self, executable):
        self._executable = executable
    def __call__(self, *args, **kwargs):
        # find the input with highest priority, and then:
        args, kwargs = input.__prepare_input__(self, *args, **kwargs)
        return input.__handle_gfunc__(self, *args, **kwargs)

# this is the core function to be passed to the generic class:
def _add(a, b, out=None):
    # the generic, ndarray implementation.
    ...

# here is the publicly exposed interface:
add = GenericFunction(_add)

# now my subclasses
class MyArray(ndarray):
    # My class tweaks the execution of the function in __handle_gfunc__
    def __prepare_input__(self, gfunc, *args, **kwargs):
        return mod_input[gfunc](*args, **kwargs)
    def __handle_gfunc__(self, gfunc, *args, **kwargs):
        res = gfunc.executable(*args, **kwargs)
        # you could have called a different core func there
        return mod_output[gfunc](res, *args, **kwargs)

class MyNextArray(MyArray):
    def __prepare_input__(self, gfunc, *args, **kwargs):
        # let the superclass do its thing:
        args, kwargs = MyArray.__prepare_input__(self, gfunc, *args, **kwargs)
        # now I can tweak it further:
        return mod_input_further[gfunc](*args, **kwargs)
    def __handle_gfunc__(self, gfunc, *args, **kwargs):
        # let's defer to the superclass to handle calling the core function:
        res = MyArray.__handle_gfunc__(self, gfunc, *args, **kwargs)
        # and now we have one more crack at the result before passing it back:
        return mod_output_further[gfunc](res, *args, **kwargs)

If a gfunc is not recognized, the subclass might raise a
NotImplementedError or it might just pass the original args, kwargs on
through. I didn't write that part out because the example was already
running long. But the point is that a single entry point could be used
for any subclass, without having to worry about how to support every
subclass.

Darren


More information about the NumPy-Discussion mailing list