There are three ways to spell "defer to me" on the table (the precise details of each spelling are, of course, still open for debate):
2. class ArrayLike(numarray.DeferTo): # ...
3. class ArrayLike: _numarray_defer_to = True # ...
I'd prefer a non-registration solution since those are both aesthetically displeasing and leave you open to the situation where a class in module A gets registered by module B, but module C expects it not to be registered and everything breaks. Not all that likely, I admit, but let's avoid the registration version if we can.
The other two solutions are almost equivalent. The one case where 3 has an edge over 2 is if I have an object (not a class), I could potentially set a _numarray_defer_to on the object before passing it to numarray without having to mess with the class of the object at all. YAGNI, though.
The advantage of 2 in my view is that it *does* force you to subclass. With 3, there will be the temptation to poke into some other module and set _numarray_defer_to on some poor unsuspecting class. This has the same disadvantage as 1, that it could confuse some other poor unsuspecting module. The correct way to do get a deferred class from a third party module is to import and subclass. This works with either 2 or 3::
class Klass2(a.Klass, numarray.DeferTo): #2 #...
class Klass3(a.Klass): #3 the good way _numarray_defer_to = True # ...
A.Klass._numarray_defer_to = True #3 the evil way.
Version 2 is cleaner and encourages you to do the right thing, so I'd prefer that solution.
Todd Miller wrote:
On Mon, 2003-09-22 at 19:27, Tim Hochberg wrote:
I actually have no idea how you plan to make keyword arguments work here, perhaps you could explain that in more detail. Metaclasses are overkill, but a mixin, marker class could be used. That is, when designing a class for use with numarray, one would derive a class from a marker class in numarray::
class MyArrayLikeClass(numarray.DeferToMe): ....
Hmmm. That's not too bad. Todd, what do you think about using this logic::
def __mul__(self, operand): if isinstance(operand, DeferToMe): operand.__rmul__(self) else: self.__mul__(operand)
I like the core idea a lot. My only doubt is whether forcing the use of inheritance is appropriate / a good thing. We might also consider spelling it like:
class MyArrayLikeClass: _numarray_defer_to_me = True
class NumArray: def __mul__(self, operand): if hasattr(operand, "_numarray_defer_to_me"): return operand.__rmul__(self) else: return ufunc.multiply(self, operand)
The only case where I see a potential problem is an old-style C-extenstion that can't be subclassed. I think that might be a case of YAGNI though.
Sounds YAGNI to me.
Avoiding registration is appealing.
Good to have this seconded.
All in all, great ideas!