11

I need to call unparameterised method first, but also parameterized first, but it is giving an error.

>>> class A:
...     def first(self):
...             print 'first method'
...     def first(self,f):
...             print 'first met',f
...
>>> a=A()
>>> a.first()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: first() takes exactly 2 arguments (1 given) 

Is it possible to do method overloading in Python like in Java?

1
  • 1
    Please inherit from object! You don't really want an old-style class, do you? (This would be a non-issue in Python 3, but your print statements tell me that you're using Python 2.) Commented Mar 15, 2012 at 20:12

6 Answers 6

13

Your second first method is overriding the original first method. In Python, it is not possible to create overloaded methods the same way as in Java.

However, you can create methods with optional and/or keyword-based arguments and process those accordingly. Here's an example:

class A:
    def first(self, f=None):
        if f is not None:
            print 'first met', f
        else:
            print 'first method'

Usage:

a = A()
a.first()
a.first('something')
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah. The default argument style of python is actually more concise, and, imo, easier to read and maintain then the Java-style giant list of overridden methods with decreasing numbers of arguments.
7

Python doesn't do function overloading. This is a consequence of it being a loosely-typed language. Instead you can specify an unknown number of arguments and deal with their interpretation in the function logic.

There are a couple ways you can do this. You can specify specific optional arguments:

def func1(arg1, arg2=None):
    if arg2 != None:
        print "%s %s" % (arg1, arg2)
    else:
        print "%s" % (arg1)

Calling it we get:

>>> func1(1, 2)
1 2

Or you can specify an unknown number of unnamed arguments (i.e. arguments passed in an array):

def func2(arg1, *args):
    if args:
        for item in args:
            print item
    else:
        print arg1

Calling it we get:

>>> func2(1, 2, 3, 4, 5)
2
3
4
5

Or you can specify an unknown number of named arguments (i.e. arguments passed in a dictionary):

def func3(arg1, **args):
    if args:
        for k, v in args.items():
            print "%s %s" % (k, v)
    else:
        print arg1

Calling it we get:

>>> func3(1, arg2=2, arg3=3)
arg2 2
arg3 3

You can use these constructions to produce the behaviour you were looking for in overloading.

1 Comment

Your func1() doesn't behave as a called might expect when it's called as func1(1, 0)
6

Usually you can only define one method in a class with a given name. In your example the 2 argument first() method overwrote the 1 argument first(). If you want two methods with the same name, in python 3 you have to use functools.singledispatch, and map the instance method name to your static method dispatcher, Ouch!

That said, I really like implicit dynamic dispatch in OO programming, and I find it cleaner than writing manual dispatch logic in some kind of 'master' first() function, which is repetitive and brittle to extension.

Challenge question: add another method like A.first(A arg).

You'll probably learn a lot about the python type system if you try to do this!

#!/opt/local/bin/python3.4

from functools import singledispatch;

class A(object):

    # default method handles dispatch for undefined types
    # note reversed positional args to match single dispatch functools
    @singledispatch
    def _first(self,arg):
        raise TypeError("no match for A._first(%s)" % type(arg));

    # adapter maps instance call to (reversed) static method call
    def first(self, arg = None): return A._first(arg, self);

    # def first()
    @_first.register(type(None))
    def _(self,none):
        print("A.first() called");

    # def first(float f)
    @_first.register(float)
    def _(self,f):
        print("A.first(float %s) called" % f);

a = A();
a.first();              # A.first() called
a.first(None);          # A.first() called
a.first(3.14);          # A.first(float 3.14) called

class B(object): pass;
b = B();                
try: a.first(b);        # no match for A._first(<class '__main__.B'>)
except TypeError as ex: print(ex);

1 Comment

Oh, that's clever :-)
0

Python is not C++ or Java; you can't overload methods in the same way.

Really, the only way to do what you want is to test for the presence or absence of the second parameter:

class A:
   def first(self, f=None):
      if f is None:
         print 'first method'
      else:
         print 'first met',f

You can be yet more sophisticated and check the type of f but that can be dangerous, and is not always "pythonic". (However, it should be mentioned that one use case for function annotations in Python 3 is to allow this sort of "Generic Programming".)

Comments

0

While it is possible to create a system that appears to use overloaded methods, it's a bit involved, and not usually needed.

The usual idiom is to have possibly unneeded parameters default to None, like so:

class A:
    def first(self, f=None):
        if f is None:
            print 'first method'
        else:
            print 'first met',f

In your case, where you want different behavior based upon whether or not this is the first call to that method, this is what I would do:

class A:
    def first(self):
        print 'first method'
        self.first = self._first
    def _first(self, f):                   # '_' is convention for private name
        print 'first met',f

and sample output:

a = A()
a.first()
a.first(3)

prints:

first method
first met 3

Comments

0

Check this code if it is helpful:

from math import pi

class Geometry:

    def area(self,length = None,breadth = None,side = None,radius = None):
        self.length = length
        self.breadth = breadth
        self.side = side
        self.radius = radius

        if length != None and breadth != None:
            return length * breadth
        elif side != None:
            return side * side
        else:
            return pi * radius * radius

obj1 = Geometry()
print('Area of rectangle is {0}.'.format(obj1.area(length=5,breadth=4)))
print('Area of square is {0}.'.format(obj1.area(side=5)))
print('Area of circle is {0:.6}.'.format(obj1.area(radius=10)))

1 Comment

The question is about method overloading in python.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.