Hi Todd,
Glad to have you back. I hope you suffered no permanant damage from the hurricane. Or the worm for that matter.
Todd Miller wrote:
On Thu, 2003-09-18 at 19:18, Tim Hochberg wrote:
Sorry for the delay; I was pretty much shut down by hurricane Isabelle from the end of last week.
I hit and bypassed this issue trying to port MA.
[SNIP]
Looking in Python's Objects/abstract.c, the function binop1 shows one way to squirm around this issue: subclass from NumArray. It would be interesting to know how Numeric does it.
I think that since Numeric arrays are C classes, they always defer to any Python class although I'm not sure of the details. In any event, I'm pretty sure it's an accident.
In my case I'm thinking of proxy objects that don't do some computations till they are actually required. So my current thinking is that __mul__ and friends would be best implemented as::
def __mul__(self, operand): if not isinstance(operand, knownTypes):
If the "not" belongs there, I'm lost.
It does belong there. KnownTypes (perhaps _numarray_nondeferred_types) would be a better term) are types that numarray knows that it should handle itself. Let me reverse the logic -- maybe it'll be clearer.
def __mul__(self, operand): if isinstance(operand, _numarray_nondeferred_types): return operand.__rmul__(self) else: try: return ufunc.multiply(self, operand) except: return operand.__rmul__(self)
I agree with your heuristic, but I am leery of putting an unqualified try/except in front of the numarray ufunc code. On the other hand, qualifying it seems too complicated.
I agree on all counts.
What about adding a tuple of types to be deferred to?
def __mul__(self, operand): if isinstance(operand, _numarray_deferred_types): operand.__rmul__(self) else: self.__mul__(operand)
Then other libraries could register classes with something like:
numarray.defer_to(my_class)
which is slightly painful, but avoids masking the ufunc exceptions and only needs to be done once for each library base class. How does that sound?
I agree that using try/except is probably not worth the danger. However, I think I'd prefer the inverse of what you propose. That is:
def __mul__(self, operand): if isinstance(operand, _numarray_nondeferred_types): self.__mul__(operand) else: operand.__rmul__(self)
and of course a dont_defer_to registration function. Hopefully with a better name. The choice comes down to whether we defer by default or handle by default. I'm marginally on the side of deferring, but don't feel too strongly either way. Either one would be a big improvement.
Perhaps someone else out there has some profound thoughts.
-tim
Todd
-tim
import numarray as na import Numeric as np
class Zero: def __add__(self, other): return other __radd__ = __add__ zero = Zero()
#~ print zero + np.arange(5) #~ print np.arange(5) + zero #~ print zero + na.arange(5) #~ print na.arange(5) + zero
a = na.arange(5)
import copy copy.deepcopy(a)