Overloading operators

M

Mr.SpOOn

Hi,
in a project I'm overloading a lot of comparison and arithmetic
operators to make them working with more complex classes that I
defined.

Sometimes I need a different behavior of the operator depending on the
argument. For example, if I compare a object with an int, I get a
result, but if I compare the same object with a string, or another
object, I get another result.

What is the best way to do this? Shall I use a lot of "if...elif"
statements inside the overloaded operator? Or is there a more pythonic
and dynamic way?
 
A

Aaron \Castironpi\ Brady

Hi,
in a project I'm overloading a lot of comparison and arithmetic
operators to make them working with more complex classes that I
defined.

Sometimes I need a different behavior of the operator depending on the
argument. For example, if I compare a object with an int, I get a
result, but if I compare the same object with a string, or another
object, I get another result.

What is the best way to do this? Shall I use a lot of "if...elif"
statements inside the overloaded operator? Or is there a more pythonic
and dynamic way?

Multimethods do the thing you're looking for. Google: 'python
multimethods' gives:

http://www.artima.com/weblogs/viewpost.jsp?thread=101605

by van Rossum. Some examples:

from mm import multimethod

@multimethod(int, int)
def foo(a, b):
...code for two ints...

@multimethod(float, float):
def foo(a, b):
...code for two floats..

It is especially good if you're using inheritance. You could also
collect the names of the types, and call a function by name:

(untested)
fname= a.__class__.__name__+ '_'+ b.__class__.__name__
or
fname= re.sub( '[^a-Za-z0-9]+', '', str( type( a ) ) ) + same
type( b )
ffunc= getattr( namespace, fname )

or build a dictionary.

(untested)
f= {}
f[ int, int ]= compA
f[ int, str ]= compB
....
ffunc= f[ type( a ), type( b ) ]

What's your favorite?
 
R

Robert Lehmann

Hi,
in a project I'm overloading a lot of comparison and arithmetic
operators to make them working with more complex classes that I defined.

Sometimes I need a different behavior of the operator depending on the
argument. For example, if I compare a object with an int, I get a
result, but if I compare the same object with a string, or another
object, I get another result.

What is the best way to do this? Shall I use a lot of "if...elif"
statements inside the overloaded operator? Or is there a more pythonic
and dynamic way?

If all your comparison methods do more or less the same (even if not but
then it will be kinda less useful for complex operations) you could use
dictionary-based dispatching. You would basically construct a dictionary
of type->comparator mappings, like this::

dispatch = {
int: int_compare_function,
str: str_compare_function,
}

And dispatch according to the other object's type::

def __cmp__(self, other):
return dispatch[type(other)]()

(Assuming good faith and just throwing a `KeyError` for unimplemented
types.)

If you just needed to dispatch on a special attribute depending on the
other object's type, you could redesign the dispatch dictionary to be a
type->attribute mapping and go somewhere along this way::

dispatch = {
int: 'value',
str: 'name',
}
def __cmp__(self, other):
return cmp(getattr(self, dispatch[type(other)]), other)

HTH,
 
A

Aaron \Castironpi\ Brady

Hi,
in a project I'm overloading a lot of comparison and arithmetic
operators to make them working with more complex classes that I
defined.

Sometimes I need a different behavior of the operator depending on the
argument. For example, if I compare a object with an int, I get a
result, but if I compare the same object with a string, or another
object, I get another result.

What is the best way to do this? Shall I use a lot of "if...elif"
statements inside the overloaded operator? Or is there a more pythonic
and dynamic way?

Off topic.
For the record, the solution in C is pretty bad without using true
overloading. There's no literal hash, and you have to carry your
types with your variables, possibly using a union. But if so, you can
use an enum and an array. This owes to the uniformity of function
signatures of the comparitors you're using.

(uncompiled)

typedef ( int comparitor_t* )( void* ob1, void* ob2 );
comparitor_t comparitors[]= { compare_ints, compare_strs /*,
others*/ };
enum comparison_types {
ints= 0,
strs= 1
};
struct variant {
comparison_types type;
union {
int i;
str s;
};
};

int compare( variant& a, variant& b ) {
assert( a.type== b.type );
return comparitors[ a.type ]( a, b );
}

'compare' knows how to retrieve its members from the union. The 'int'
comparitor accesses the 'i' field, &c. Your compiler needs to know
that enums are ints or that they can be indices into an array.

For BASIC and even VisualBasic up to version 6, you have no choice but
use a switch statement. The addressof operator won't help since
you're not calling DLL entry points. VisualBasic.NET claims to
overload functions. But C++ and VB can both employ the Visitor
pattern "double-dispatch". It would be good practice to use Visitor
to keep your options open across more languages, except that it's kind
of trivial in Python, oddly enough. Good middle ground, I guess.
 
K

Kay Schluehr

Hi,
in a project I'm overloading a lot of comparison and arithmetic
operators to make them working with more complex classes that I
defined.

Sometimes I need a different behavior of the operator depending on the
argument. For example, if I compare a object with an int, I get a
result, but if I compare the same object with a string, or another
object, I get another result.

What is the best way to do this? Shall I use a lot of "if...elif"
statements inside the overloaded operator? Or is there a more pythonic
and dynamic way?

I can't see anything wrong about it. Sometimes I try to avoid
isinstance() though because it is a rather slow operation. If the
majority of operations is single-typed one can also use a try-stmt:

def __add__(self, other):
try:
return self._val + other
except TypeError:
return self.__add__(SomeWrapper(other))

and compare performance using a profiler. Notice that also

if type(obj) == T:
BLOCK

is much faster than isinstance() but it's not OO-ish and very rigid.
 
M

Mr.SpOOn

Thanks for the suggestion. I think I'm gonna try the multimethods way,
that I didn't know about it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top