Method overloading?

P

placid

Hi all,

Is it possible to be able to do the following in Python?

class Test:
def __init__(self):
pass

def puts(self, str):
print str

def puts(self, str,str2):
print str,str2

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")


Cheers
 
G

Grant Edwards

Is it possible to be able to do the following in Python?

class Test:
def __init__(self):
pass

def puts(self, str):
print str

def puts(self, str,str2):
print str,str2

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")

You tell us: what happened when you tried it?

And then what happens when you do this?

class Test:
def __init__(self):
pass

def puts(self, *args):
print ' '.join(args)

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")

Now an exercise for the gentle reader: change the puts method
so that this call works:

t.puts("hi",1,3.45)
 
P

placid

You tell us: what happened when you tried it?

Well, when i run it i get this error "puts() takes exactly 3 arguments
(2 given)" which means that the second a time i try to define the
puts() method "overwrites" the first one
And then what happens when you do this?

class Test:
def __init__(self):
pass

def puts(self, *args):
print ' '.join(args)

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")

but this isn't overloading.
 
P

Paul McGuire

Hi all,

Is it possible to be able to do the following in Python?

class Test:
def __init__(self):
pass

def puts(self, str):
print str

def puts(self, str,str2):
print str,str2

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")

Cheers

No, Python does not do overloading as part of the language, you have
to do the variable argument interpretation for yourself.

For instance, if you want a method to accept a single argument of
various types, it would look something like this:

def multiAccept( argOfVariousTypes ):
if isinstance(argOfVariousTypes,int):
# treat like an int
elif isinstance(argOfVariousTypes,float):
# treat like a float
elif isinstance(argOfVariousTypes,(list,tuple)):
# treat like a container

This is not really all that Pythonic a style. More generally accepted
is to just *use* the arg in the way you want, and throw exceptions
when the arg doesn't conform - if the user sends invalid args, let him/
her deal with the resulting exceptions.

Here's a method that will handle an arg of various types:

def containerStats(cont):
print "Container is of type %s" % cont.__class__.__name__
print "- min value is", min(cont)
print "- max value is", max(cont)
print "- length is", len(cont)
Container is of type list
- min value is 1
- max value is 3
- length is 3Container is of type tuple
- min value is 123
- max value is def
- length is 3Container is of type dict
- min value is a
- max value is c
- length is 3Container is of type str
- min value is ;
- max value is s
- length is 9

What's really interesting, is that this method could have been written
back in Python 1.5 days, and in Python 2.3 with the introduction of
sets, we could use this new data type, which didn't even exist when
the original code was written, and get some interesting results:
Container is of type set
- min value is D
- max value is S
- length is 6


And if we don't send a container? This happens:
Container is of type float
- min value is
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in containerStats
TypeError: iteration over non-sequence

But what did I expect, sending a single float to a method that clearly
expects a sequence of some kind?!

Python does include in the language the ability to send a variable
number of arguments to a method, using *args and **kwargs. Your
original puts method can accept a variable argument list in something
like this:

class Test:
def __init__(self):
pass

def puts(self, *args):
print " ".join(map(str,args))

if __name__ == "__main__":
t = Test()
t.puts("hi")
t.puts("hi","hello")
t.puts("hi",1,3.45)

Prints:
hi
hi hello
hi 1 3.45

Combine these techniques, and you can overload your methods to your
heart's content!

-- Paul
 
S

Steven D'Aprano

Well, when i run it i get this error "puts() takes exactly 3 arguments
(2 given)" which means that the second a time i try to define the
puts() method "overwrites" the first one

Yes, that's right. It is no different from doing this:

x = 1
x = 2

but this isn't overloading.

Neither was your first example.


This is an example of overloading:

class Cheese(object):
def flavour(self):
return "tasty and scrumptious"
def colour(self):
return "yellow"


Now we define a sub-class which overloads some methods:

class BlueVein(Cheese):
def colour(self):
return "white with blue veins"

Testing it:

'yellow'


I hope this helps.
 
S

Steven D'Aprano

No, Python does not do overloading as part of the language, you have
to do the variable argument interpretation for yourself.

For instance, if you want a method to accept a single argument of
various types, it would look something like this:

def multiAccept( argOfVariousTypes ):
if isinstance(argOfVariousTypes,int):
# treat like an int
elif isinstance(argOfVariousTypes,float):
# treat like a float
elif isinstance(argOfVariousTypes,(list,tuple)):
# treat like a container

Is that really called "overloading"? I've never (knowingly) come across
the term being used in that context before. I've always known that as
"multiple dispatch" or "polymorphism", depending on whether you or the
compiler handles the dispatching.

Actually, I tell a lie. I've always know it as "a function that can handle
different types of arguments" :)
 
P

Paul McGuire

Is that really called "overloading"? I've never (knowingly) come across
the term being used in that context before. I've always known that as
"multiple dispatch" or "polymorphism", depending on whether you or the
compiler handles the dispatching.

Well, I think "overloading" and "Python" may not even belong in the
same sentence, actually. "Overloading" is used in C++, Java and C# to
describe a single method name with multiple signatures. It is not
really possible to implement such a thing in Python, which just binds
methods to names, and duplicate definitions of methodX just replace
the former with the latter.

But from the standpoint of the caller, calls to methodX() with various
numbers and types of arguments looks just the same as it does in Java
or C# with method overloading, and could reasonably be thought of as
such - what does the caller care how methodX handles these various
calls, whether with 1 hyper-adaptive method implementation or a dozen
type-specific ones?

I've had this discussion before, but I personally tend to reserve the
term "polymorphism" for instance-level behavior, such as when a
collection of instances that all derive from a common base class have
overridden method definitions. The typical example is a list of
Shapes, each implementing its own draw() method, so that they
polymorphically do their subclass-appropriate draw behavior. Or for a
Strategy pattern implementation (one of my favorite), where derived
strategy classes implement a base interface with their separate
behaviors, and each is accessed through the interface definition.

The beauty of Python's duck-typing is that this same kind of
polymorphism can be achieved without the burden of class inheritance
hierarchies. As long as the instances referenced all implement
methodX(), Python is happy. If I'm desperate, I could even
dynamically attach a do-nothing or default version of such a method if
it were not already defined for an instance. Try *that* in C++
(without a horrifying haystack of angle brackets)!

I have heard "overloading" referred to as "method polymorphism", but I
think this is just a dilution of the "polymorphism" term, with no
additional knowledge transfer gained.

-- Paul
 
T

Troy Melhase

class Test:
def __init__(self):
pass

def puts(self, str):
print str

def puts(self, str,str2):
print str,str2

you might look into the overloading module and its decorator. source
is in the sandbox:

http://svn.python.org/view/sandbox/trunk/overload/overloading.py

using it, you could re-write your example as:

#
from overloading import overloaded

class Test(object):

@overloaded
def puts(self, S):
print S

@puts.register(object, str, str)
def puts_X(self, S, S2):
print S, S2

two things to note. first, i changed your class to derive from
object. I don't know if that's required, but i suspect it is.

second, i changed your argument names. the argument names in your
example shadow built-in names. you shouldn't do that in any case, but
it could become especially confusing using the overloaded decorator,
which relies on argument type to select the correct method.
 
G

Grant Edwards

Well, when i run it i get this error "puts() takes exactly 3 arguments
(2 given)" which means that the second a time i try to define the
puts() method "overwrites" the first one

Correct. That means it's not possible to do what you wrote.
but this isn't overloading.

No, it isn't. [You can't overload methods in Python. Was that
your question?] It is, however, the way one does what you
appear to be trying to do.
 
N

Neil Cerutti

Is that really called "overloading"? I've never (knowingly)
come across the term being used in that context before. I've
always known that as "multiple dispatch" or "polymorphism",
depending on whether you or the compiler handles the
dispatching.

It's due to vague terminology that we're using.

What the OP wanted to know about was static polymorphism of names
based on function signatures, often refered to informally in the
context of C++ as "function overloading", though it's really
"identifier overloading where identifier refers to a function or
member function".

What Python provides is dynamic polymorphism of names with
single-dispatch.

I think. ;-)
 
P

placid

It's due to vague terminology that we're using.

What the OP wanted to know about was static polymorphism of names
based on function signatures, often refered to informally in the
context of C++ as "function overloading", though it's really
"identifier overloading where identifier refers to a function or
member function".

This what i was asking.
What Python provides is dynamic polymorphism of names with
single-dispatch.

I think. ;-)

Thank you all for the information.
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top