472,139 Members | 1,680 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,139 software developers and data experts.

Overloading operators

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?
Oct 15 '08 #1
5 1332
On Oct 15, 7:34*am, Mr.SpOOn <mr.spoo...@gmail.comwrote:
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/viewpo...?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?
Oct 15 '08 #2
On Wed, 15 Oct 2008 14:34:14 +0200, Mr.SpOOn wrote:
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,

--
Robert "Stargaming" Lehmann
Oct 15 '08 #3
On Oct 15, 7:34*am, Mr.SpOOn <mr.spoo...@gmail.comwrote:
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.
Oct 15 '08 #4
On 15 Okt., 14:34, Mr.SpOOn <mr.spoo...@gmail.comwrote:
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.
Oct 16 '08 #5
Thanks for the suggestion. I think I'm gonna try the multimethods way,
that I didn't know about it.
Oct 16 '08 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

13 posts views Thread by denis wendum | last post: by
2 posts views Thread by bq | last post: by
20 posts views Thread by KL | last post: by
18 posts views Thread by uday | last post: by
5 posts views Thread by Jerry Fleming | last post: by
3 posts views Thread by johnmmcparland | last post: by
15 posts views Thread by PengYu.UT | last post: by
7 posts views Thread by Rahul | last post: by
2 posts views Thread by jimzat | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.