[Numpy-discussion] replacing the mechanism for dispatching ufuncs
Wed Jun 22 17:56:29 CDT 2011
On Wed, Jun 22, 2011 at 4:57 PM, Darren Dale <email@example.com> wrote:
> On Wed, Jun 22, 2011 at 1:31 PM, Mark Wiebe <firstname.lastname@example.org> wrote:
> > On Wed, Jun 22, 2011 at 7:34 AM, Lluís <email@example.com> wrote:
> >> Darren Dale writes:
> >> > On Tue, Jun 21, 2011 at 1:57 PM, Mark Wiebe <firstname.lastname@example.org>
> >> >> On Tue, Jun 21, 2011 at 12:36 PM, Charles R Harris
> >> >> <email@example.com> wrote:
> >> >>> How does the ufunc get called so it doesn't get caught in an endless
> >> >>> loop?
> >> > [...]
> >> >> The function being called needs to ensure this, either by extracting
> >> >> raw
> >> >> ndarray from instances of its class, or adding a 'subok = False'
> >> >> parameter
> >> >> to the kwargs.
> >> > I didn't understand, could you please expand on that or show an
> >> As I understood the initial description and examples, the ufunc overload
> >> will keep being used as long as its arguments are of classes that
> >> declare ufunc overrides (i.e., classes with the "_numpy_ufunc_"
> >> attribute).
> >> Thus Mark's comment saying that you have to either transform the
> >> arguments into raw ndarrays (either by creating new ones or passing a
> >> view) or use the "subok = False" kwarg parameter to break a possible
> >> overloading loop.
> > The sequence of events is something like this:
> > 1. You call np.sin(x)
> > 2. The np.sin ufunc looks at x, sees the _numpy_ufunc_ attribute, and
> > x._numpy_ufunc_(np.sin, x)
> > 3. _numpy_ufunc_ uses np.sin.name (which is "sin") to get the correct
> > function to call
> > 4A. If my_sin called np.sin(x), we would go back to 1. and get an
> > loop
> > 4B. If x is a subclass of ndarray, my_sin can call np.sin(x,
> > as this disables the subclass overloading mechanism.
> > 4C. If x is not a subclass of ndarray, x needs to produce an ndarray, for
> > instance it might have an x.arr property. Then it can call np.sin(x.arr)
> Ok, that seems straightforward and, for what its worth, it looks like
> it would meet my needs. However, I wonder if the _numpy_func_
> mechanism is the best approach. This is a bit sketchy, but why not do
> something like:
> class Proxy:
> def __init__(self, ufunc, *args):
> self._ufunc = ufunc
> self._args = args
> def __call__(self, func):
> self._ufunc._registry[tuple(type(arg) for arg in self._args)] = func
> return func
> class UfuncObject:
> def __call__(self, *args, **kwargs):
> func = self._registry.get(tuple(type(arg) for arg in args), None)
> if func is None:
> raise TypeError
> return func(*args, **kwargs)
> def register(self, *args):
> return Proxy(self, *args)
> def sin(pq):
> if pq.units != degrees:
> pq = pq.rescale(degrees)
> temp = np.sin(pq.view(np.ndarray))
> return Quantity(temp, copy=False)
> This way, classes don't have to implement special methods to support
> ufunc registration, special attributes to claim primacy in ufunc
> registration lookup, special versions of the functions for each numpy
> ufunc, *and* the logic to determine whether the combination of
> arguments is supported. By that I mean, if I call np.sum with a
> quantity and a masked array, and Quantity wins the __array_priority__
> competition, then I also need to check that my special sum function(s)
> know how to operate on that combination of inputs. With the decorator
> approach, I just need to implement the special versions of the ufuncs,
> and the decorators handle the logic of knowing what combinations of
> arguments are supported.
> It might be worth considering using ABCs for registration and have
> UfuncObject use isinstance to determine the appropriate special
> function to call.
The thing I'm not sure about with this idea is how to do something general
to modify all ufuncs for a particular class in one swoop. Having to
individually override everything would be a hassle, I think. I also don't
think this approach saves very much effort compared to the _numpy_ufunc_
call approach, checking the types and raising NotImplemented if they aren't
what's wanted is pretty much the only difference, and that check could still
be handled by a decorator like you're showing.
> NumPy-Discussion mailing list
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the NumPy-Discussion