[Numpy-discussion] metadata and metabehavior for arrays (for scipy.base or Numeric3)

David M. Cooke cookedm at physics.mcmaster.ca
Thu Apr 7 01:08:11 EDT 2005


konrad.hinsen at laposte.net writes:

> On 07.04.2005, at 00:43, David M. Cooke wrote:
>
>> I like this! It's got namespace goodness all over it (last Python zen
>> line in 'import this': Namespaces are one honking great idea -- let's
>> do more of those!)
>
> Sounds like a good principle!
>
>> 1) arrays. Here, we want efficient computation of functions applied to
>>    lots of elements. That's where the output arguments and special
>>    methods (.reduce, .accumulate, and .outer) are useful
>
> All that is accessible if the class gets passed the ufunc object.
>
>> 2) polymorphic functions. Output arguments aren't useful here. The
>>    special methods are useful for binary ufuncs only.
>
> Fine, then they just call the ufunc. And the rare cases that need
> explicit code for each ufunc (my Derivatives, for example) can
> retrieve  the name of the ufunc and dispatch on it.

Hmm, I had misread your previous code. Here it is again, made more
specific, and I'll assume this function lives in the ndarray package
(as there is more than one package that defines ufuncs)

def cos(obj):
    if ndarray.isarray(obj):
        return ndarray.array_cos(obj)
    else:
        try:
            return obj.__ufunc__(cos)
        except AttributeError:
            if ndarray.is_array_like(obj):
                a = ndarray.array(obj)
                return ndarray.array_cos(a)
            else:
                raise ValueError

The thing is obj.__ufunc__ must understand about the *particular*
object cos: the ndarray one. I was thinking more along the lines of
obj.__ufunc__('cos'), where the name is passed instead.

For binary ufuncs, you could use (with arguments obj1 and obj2),
obj1.__ufunc__('add', obj2)

Output argument (obj3): obj1.__ufunc__('add', obj2, obj3)
Special methods:
    obj1.__ufunc__('add.reduce')
    obj1.__ufunc__('add.accumulate')
    obj1.__ufunc__('add.outer', obj2)

Basically, special methods are just another ufunc. This suggests that
add.outer should optionally take an output argument...

Alternatively, __ufunc__ could be an object of implemented ufuncs:

obj.__ufunc__.cos()
obj1.__ufunc__.add(obj2)
obj1.__ufunc__.add(obj2, obj3)
obj1.__ufunc__.add.reduce()
obj1.__ufunc__.add.accumulate()
obj1.__ufunc__.add.outer(obj2)

It depends where you want to do the dispatch. I think this version is
better: it's easier to discover what __ufunc__'s are supported with
generic tools (IPython tab completion, pydoc, etc.).

-- 
|>|\/|<
/--------------------------------------------------------------------------\
|David M. Cooke                      http://arbutus.physics.mcmaster.ca/dmc/
|cookedm at physics.mcmaster.ca




More information about the NumPy-Discussion mailing list