[Numpy-discussion] using numpy functions on an array of objects

Robert Kern robert.kern@gmail....
Sat Jan 31 17:24:52 CST 2009

On Sat, Jan 31, 2009 at 10:30, Sebastian Walter
<sebastian.walter@gmail.com> wrote:
> Wouldn't it be nice to have numpy a little more generic?
> All that would be needed was a little check of the arguments.
> If I do:
> numpy.trace(4)
> shouldn't numpy be smart enough to regard the 4 as a 1x1 array?

Why? It's not a 1x1 array. It's a scalar. If you want a 1x1 array,
give it a 1x1 array.

> numpy.sin(4) works!

Yes, numpy.sin() operates on scalars in addition to arrays.

> and if
> x = my_class(4)
> wouldn't it be nice if
> numpy.trace(x)
> would call
> x.trace() ?
> numpy.sin(my_class(4)) works!
> Wouldn't it be nice if numpy worked a little more consistent.
> Is this worth a ticket? Or am I missing something here?

numpy.sin() is a ufunc. Unary ufuncs will call the method of the same
name on objects in an object array (or the scalar itself if given an
object scalar). For example:

In [8]: class MyClass(object):
   ...:     def __init__(self, x):
   ...:         self.x = x
   ...:     def __repr__(self):
   ...:         return 'MyClass(%r)' % (self.x,)
   ...:     def sin(self):
   ...:         return MyClass(self.x+1)

In [9]: sin(MyClass(4))
Out[9]: MyClass(5)

In [10]: sin([MyClass(4), MyClass(5)])
Out[10]: array([MyClass(5), MyClass(6)], dtype=object)

You'll notice that numpy.sin() does not try to call the list.sin()
method when given the list. It interprets it as an object array, and
calls the MyClass.sin() method on each of the elements.

numpy.trace() is not an unary ufunc. It's just a function that
operates on (N>=2)-D arrays. You simply couldn't apply the same rules
as numpy.sin(). Otherwise, it would try to call the .trace() method on
each of the objects in your container, and obviously you can't
implement trace that way.

Having numpy.trace(x) simply call x.trace() would not be making numpy
more consistent.

Now, that said, the implementation of numpy.trace(x, *args) is
actually simply asarray(x).trace(*args). That should probably be
asanyarray(x) in order to allow ndarray subclasses. But this only
works because ndarray.trace() already exists. Making every function in
numpy check for a method first is just not going to happen.

Robert Kern

"I have come to believe that the whole world is an enigma, a harmless
enigma that is made terrible by our own mad attempt to interpret it as
though it had an underlying truth."
  -- Umberto Eco

More information about the Numpy-discussion mailing list