237

I am trying to implement method overloading in Python:

class A:
    def stackoverflow(self):    
        print ('first method')
    def stackoverflow(self, i):
        print ('second method', i)

ob=A()
ob.stackoverflow(2)

but the output is second method 2; similarly:

class A:
    def stackoverflow(self):    
        print ('first method')
    def stackoverflow(self, i):
        print ('second method', i)

ob=A()
ob.stackoverflow()

gives

Traceback (most recent call last):
  File "my.py", line 9, in <module>
    ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)

How do I make this work?

AsukaMinato
  • 1,017
  • 12
  • 21
user1335578
  • 2,587
  • 2
  • 18
  • 15
  • 58
    In Python, think of methods as a special set of "*attributes*", and there can only be one "*attribute*" (and thus one method) of a given name for an object. The last method *overwrites* any previous methods. In Java, methods are not first-class citizens (they are not "attributes of objects"), but are rather invoked by "sending messages" that are are statically resolved based on closest type (which is where *overloading* comes in). –  Apr 18 '12 at 05:06
  • 2
    Also see http://stackoverflow.com/questions/733264/function-overloading-in-python-missing – agf Apr 18 '12 at 05:08
  • 2
    and http://stackoverflow.com/questions/6434482/python-function-overloading – agf Apr 18 '12 at 05:32
  • 7
    Why is none of the answers to this question accepted yet? Just click on the outlied check mark on the left of your favourite answer... – glglgl May 22 '12 at 09:34
  • 2
    possible duplicate of [Overloaded functions in python?](http://stackoverflow.com/questions/7113032/overloaded-functions-in-python) – Ciro Santilli OurBigBook.com Jul 14 '15 at 18:47
  • try reading https://learnbatta.com/blog/method-overloading-in-python-60/ – anjaneyulubatta505 Dec 08 '18 at 07:29
  • Related (not duplicate): *[How can I detect duplicate method names in a Python class?](https://stackoverflow.com/questions/10761988)* – Peter Mortensen Jan 06 '21 at 16:21

17 Answers17

184

It's method overloading, not method overriding. And in Python, you historically do it all in one function:

class A:
    def stackoverflow(self, i='some_default_value'):
        print('only method')

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()

See the Default Argument Values section of the Python tutorial. See "Least Astonishment" and the Mutable Default Argument for a common mistake to avoid.

See PEP 443 for information about the single dispatch generic functions added in Python 3.4:

>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...         print("Let me just say,", end=" ")
...     print(arg)
>>> @fun.register(int)
... def _(arg, verbose=False):
...     if verbose:
...         print("Strength in numbers, eh?", end=" ")
...     print(arg)
...
>>> @fun.register(list)
... def _(arg, verbose=False):
...     if verbose:
...         print("Enumerate this:")
...     for i, elem in enumerate(arg):
...         print(i, elem)
FLAK-ZOSO
  • 3,873
  • 4
  • 8
  • 28
agf
  • 171,228
  • 44
  • 289
  • 238
  • 167
    _and you don't need to_ - IMHO sometime it would be very handy to have method overloading like e.g. in C++. Ok, it is not 'needed' in the sense that it can't be done using other constructs - but it would make some things easier and simpler. – Andreas Florath Apr 18 '12 at 06:09
  • 9
    @AndreasFlorath I disagree. Learn to love duck typing and write each method so it only does one thing, and there is no need for method overloading. – agf Apr 18 '12 at 07:05
  • yeah, I need it, because I write in C++ and thus think in C++. understood now – zinking Jun 21 '13 at 06:44
  • 4
    +1 for making me read about the "common mistake to avoid" before I got caught – mdup Sep 10 '13 at 11:27
  • 86
    I would like to disagree a little bit ;) ... overloading often make code cleaner, because you don't pack the method with too many if-else statement to handle different cases. In a sense the whole gamut of functional languages use similar idea i.e. argument-pattern-matching. Which mean you would have smaller more cleaner methods.. rather than giant unreadable ones. – sten Feb 28 '16 at 19:15
  • 3
    @user1019129 That's the purpose of the single dispatch generic functions added in Python 3.4, and linked in my answer. – agf Sep 14 '16 at 13:33
  • 2
    so we have to explicitly do `if:`, `elif:` on different arguments passed to that 'single dispatch generic function' if say we needed several overloads which perform different action based on different set of arguments? – Mahesha999 Sep 27 '16 at 07:57
  • 1
    @Mahesha999 I'm not sure what you're asking. You don't need any `if`s to do dispatch on a single argument with the PEP 443 generic functions. Please read the linked document. – agf Sep 27 '16 at 15:27
  • 1
    A common misconception: Default argument values are not a substitutes for overloading. Compare `Velocity()`, representing a velocity of zero, and `Velocity(x,y,z)`. In this setting, making it callable like `Velocity(1,3)` makes no sense. Likewise, `Position(x,y,z)` vs `Position(position)`. – Sebastian Mach Jun 22 '18 at 14:26
  • 1
    Also, you say "don't need to", which is always universally correct for every feature in every real world and turing complete programming language. And then introduce PEP 443 with a cheeky tone. Hmm. – Sebastian Mach Jun 22 '18 at 14:28
  • @SebastianMach Default arguments can replace many use cases of overloading, and additional logic in the method can replace others. In the case of your examples, you could (and people often do) set defaults of None and inspect the values to see what was passed. Omitting a single argument isn't the only thing you can do with default arguments, and you can always raise an argument error if people call it in a way that doesn't make sense. – agf Jun 23 '18 at 09:46
  • @SebastianMach You don't need method overloading in Python, not because it's possible to do things in other ways, but because it's often idiomatic to. "Need" is used more generally than in the narrow definition you give in your comments on this answer and the other below. As far as PEP 443, it didn't exist when this answer was originally written. I added that later in an edit; I have no idea what you mean by "a cheeky tone" -- I just link to it and describe what it is. – agf Jun 23 '18 at 09:53
  • 3
    @agf: I am not really questioning the (non-) "need". C++ does not "need" them either, like C++ does not "need" smart pointers because one could just manage memory manually. Overloads are just another tool in the box; one that could delegate the explicit and slower manual checking of argument combinations to the interpreter to the call resolution level. As you imply, it can be tool used to increase code robustness (because when you have overloading, the interpreter does the checking for you). – Sebastian Mach Jun 25 '18 at 09:47
  • 6
    @agf: By "cheeky", I mean that answers like "it's not there because it's not needed" look downlooking to the reader, and that typically unjustified so. – Sebastian Mach Jun 25 '18 at 09:49
  • 2
    When someone describes a missing feature with "you don't need it", cognitive dissonance chimes up to a hundred miles away. Overloading is much stronger than default values for god's sake. Strong types, that proceed to solve a myriad of other issues, do not exist in python because it was born as a scripting language, and it lately tries to change it. Appreciate python as a good scripting language, but don't forget what it is. Real overloading requires prototyping that differentiates types, script langs like python don't do it and lose a lot of elegance and readability due to this. – SeventyFive Oct 22 '18 at 13:42
  • @SeventyFive I think your entire comment is wrong, and shows a lack of experience with how dynamically typed languages like Python are used at scale. However, if you look at the link at the bottom of my answer, you'll see they Python has the exact feature you're describing -- type based dispatch -- in versions 3.4+. – agf Oct 22 '18 at 14:28
  • 1
    I like Python but I certainly don't like not having method overloading. – progonkpa Apr 01 '22 at 09:22
  • @progonkpa Have you checked out [single dispatch generic functions](https://peps.python.org/pep-0443/)? – agf Apr 02 '22 at 14:18
  • @agf never heard of it, checked it out and I can see how that provides a form of method overloading. Good that it exists, thanks for that. Overloading in e.g. Java is a lot more elegant though. – progonkpa Apr 02 '22 at 14:40
111

You can also use pythonlangutil:

from pythonlangutil.overload import Overload, signature

class A:
    @Overload
    @signature()
    def stackoverflow(self):    
        print('first method')
    
    @stackoverflow.overload
    @signature("int")
    def stackoverflow(self, i):
        print('second method', i)
FLAK-ZOSO
  • 3,873
  • 4
  • 8
  • 28
Ehsan Keshavarzian
  • 1,138
  • 1
  • 9
  • 18
  • 13
    I think that's the only valid answer to the question. I would double-upvote if I could. – Michael Oct 10 '17 at 15:55
  • 3
    it's good, but it doesn't work on raw functions, just methods within a class. – MetaStack Mar 01 '19 at 23:42
  • 1
    @LegitStack That functionality can also be added. It's not impossible. – Ehsan Keshavarzian Mar 03 '19 at 23:20
  • @EhsanKeshavarzian I did add it to my own version, and it seems to work, but I don't know if I did it the right way. I also added functionality to allow a signature to be a dictionary so you can specify the name of the argument. that way you can have two functions with the same type signatures but different names and you can differentiate between the two as long as the arguments are named. – MetaStack Mar 04 '19 at 16:34
  • @LegitStack There are multiple ways of doing it. There is also https://github.com/bintoro/overloading.py But with Python 3 support of Overloading I do not think there is any need for third party libraries anymore. https://docs.python.org/3/library/typing.html#typing.overload – Ehsan Keshavarzian Mar 04 '19 at 20:33
  • The @overload-decorator is just a hint for the type checker, no? – michi7x7 Jul 18 '19 at 17:30
  • @michi7x7 if you look at [Overload source](https://github.com/ehsan-keshavarzian/pythonlangutil/blob/master/pythonlangutil/overload.py) you'll see the connection. Basically type declaration in signature decorator acts like a key to register the method instance. Then when the method is called, the actual signature will be generated and used as a key to select correct instance of the method. – Ehsan Keshavarzian Jul 19 '19 at 01:08
  • @EhsanKeshavarzian sure, but that still is your pythonlangutil. There is no "official support for overloading" yet. – michi7x7 Jul 19 '19 at 09:39
  • @michi7x7 Sorry I thought you were asking about my code. I haven't used the official one yet. And it seems you're tight. From the description it seems to be a hint for type checker. – Ehsan Keshavarzian Jul 22 '19 at 03:09
  • 3
    @LegitStack I updated the code on GitHub, now it works with functions too. – Ehsan Keshavarzian Aug 06 '19 at 02:40
  • According to [the docs for `typing.overload`](https://docs.python.org/3/library/typing.html#typing.overload): "The @overload-decorated definitions are for the benefit of the type checker only...". So there isn't an Official method for actually dispatching the overloads. – Paul Price Aug 09 '19 at 17:20
  • 1
    @PaulPrice That's right. I updated my answer and removed the official support section. You can still use my code to dispatch overloads. It now works with both methods and functions. Grab the code from GitHub. I haven't updated PyPi yet. – Ehsan Keshavarzian Aug 12 '19 at 00:27
84

While agf was right with the answer in the past, pre-3.4, now with PEP-3124 we got our syntactic sugar.

See typing documentation for details on the @overload decorator, but note that this is really just syntactic sugar and IMHO this is all people have been arguing about ever since.

Personally, I agree that having multiple functions with different signatures makes it more readable then having a single function with 20+ arguments all set to a default value (None most of the time) and then having to fiddle around using endless if, elif, else chains to find out what the caller actually wants our function to do with the provided set of arguments. This was long overdue following the Python Zen:

Beautiful is better than ugly.

and arguably also

Simple is better than complex.

Straight from the official Python documentation linked above:

from typing import overload
@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

EDIT: for anyone wondering why this example is not working as you'd expect if from other languages I'd suggest to take a look at this discussion. The @overloaded functions are not supposed to have any actual implementation. This is not obvious from the example in the Python documentation.

smci
  • 32,567
  • 20
  • 113
  • 146
omni
  • 4,104
  • 8
  • 48
  • 67
  • exactly what I was looking for, neater than defining own overloading decorator – pcko1 Dec 17 '19 at 15:11
  • 12
    Crazy, had to scroll through at least 5 "Thou shalt not do that!!" to get to this, an actually answers to the questions. Thanks @masi! – th3coop Oct 21 '20 at 03:13
  • 3
    @th3coop that's somewhat to be expected with how old the question and earlier answers are. At the time, the answer really was "you can do it with a hack, but you probably shouldn't". Once there was an actual way included in the standard library, its easy to recommend that. I know StackOverflow is working on a way to sort by the most relevant answer rather than just the one that has had the most time to accumulate upvotes. – Tyberius Dec 03 '21 at 19:49
51

In Python, you don't do things that way. When people do that in languages like Java, they generally want a default value (if they don't, they generally want a method with a different name). So, in Python, you can have default values.

class A(object):  # Remember the ``object`` bit when working in Python 2.x

    def stackoverflow(self, i=None):
        if i is None:
            print 'first form'
        else:
            print 'second form'

As you can see, you can use this to trigger separate behaviour rather than merely having a default value.

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form
Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
  • 3
    Mostly `None` is useful when you want a mutable default value. Separate behavior should be in separate functions. – agf Apr 18 '12 at 04:58
  • @agf: `None` can also be useful as a genuine default value. – Chris Morgan Apr 18 '12 at 04:59
  • Yes, but I was referring to using it as a sentinel value, which is how you use it in your answer, and as I think my comment makes clear. – agf Apr 18 '12 at 05:02
  • you say "generally"? are you implying this isn't always so? – joel Jul 25 '19 at 21:37
  • No, people want the function to behave differently, not have a "default value." Slightly different behaviors for different argument types and argument count. – Gordon Zar Jan 12 '22 at 10:56
23

You can't, never need to and don't really want to.

In Python, everything is an object. Classes are things, so they are objects. So are methods.

There is an object called A which is a class. It has an attribute called stackoverflow. It can only have one such attribute.

When you write def stackoverflow(...): ..., what happens is that you create an object which is the method, and assign it to the stackoverflow attribute of A. If you write two definitions, the second one replaces the first, the same way that assignment always behaves.

You furthermore do not want to write code that does the wilder of the sorts of things that overloading is sometimes used for. That's not how the language works.

Instead of trying to define a separate function for each type of thing you could be given (which makes little sense since you don't specify types for function parameters anyway), stop worrying about what things are and start thinking about what they can do.

You not only can't write a separate one to handle a tuple vs. a list, but also don't want or need to.

All you do is take advantage of the fact that they are both, for example, iterable (i.e. you can write for element in container:). (The fact that they aren't directly related by inheritance is irrelevant.)

bgse
  • 8,237
  • 2
  • 37
  • 39
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • 16
    TBH, I would be more careful with "never need to". This is something that can be tagged upon every feature of any real world and turing complete programming language, and therefore is not a valid argument. Who _needs_ generators? Who _needs_ classes? Programming languages are just syntactic sugar to something more concrete. – Sebastian Mach Jun 22 '18 at 14:30
  • 13
    Completely disagree. It may be that you "never needed to" or "never wanted to", but there are enough applications where you desparately want to. Try e.g. writing a program that handles both Python and numpy arrays gracefully without littering your program with instanceof's ... – Elmar Zander Aug 22 '18 at 19:29
  • 3
    Based on masi's answer, I'd say that "you can't" is now incorrect and obsolete. Based on the existence of the `@overload` decorator, I'd say that "don't really want to" is arguable, at best. From PEP-3124, "...it is currently a common anti-pattern for Python code to inspect the types of received arguments...the 'obvious way' to do this is by type inspection, but this is brittle and closed to extension..." So it seems as if enough people wanted to, that it became part of Python. – Mike S Nov 16 '18 at 22:09
  • @MikeS , the standard `@overload` is for typing only. – Noein May 12 '19 at 14:12
  • @Narfanar I don't know how your response applies to my comment. Could you explain? – Mike S May 17 '19 at 23:01
17

I think the word you're looking for is "overloading". There isn't any method overloading in Python. You can however use default arguments, as follows.

def stackoverflow(self, i=None):
    if i != None:
        print 'second method', i
    else:
        print 'first method'

When you pass it an argument, it will follow the logic of the first condition and execute the first print statement. When you pass it no arguments, it will go into the else condition and execute the second print statement.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mayhewr
  • 4,003
  • 1
  • 18
  • 15
17

I write my answer in Python 3.2.1.

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

How it works:

  1. overload takes any amount of callables and stores them in tuple functions, then returns lambda.
  2. The lambda takes any amount of arguments, then returns result of calling function stored in functions[number_of_unnamed_args_passed] called with arguments passed to the lambda.

Usage:

class A:
    stackoverflow=overload(                    \
        None, \ 
        #there is always a self argument, so this should never get called
        lambda self: print('First method'),      \
        lambda self, i: print('Second method', i) \
    )
Seyfi
  • 1,832
  • 1
  • 20
  • 35
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
13

I write my answer in Python 2.7:

In Python, method overloading is not possible; if you really want access the same function with different features, I suggest you to go for method overriding.

class Base(): # Base class
    '''def add(self,a,b):
        s=a+b
        print s'''

    def add(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c

        sum =a+b+c
        print sum

class Derived(Base): # Derived class
    def add(self,a,b): # overriding method
        sum=a+b
        print sum



add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class

add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2)   # function with 2 arguments
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Moorthi Muthu
  • 409
  • 5
  • 13
9

In Python, overloading is not an applied concept. However, if you are trying to create a case where, for instance, you want one initializer to be performed if passed an argument of type foo and another initializer for an argument of type bar then, since everything in Python is handled as object, you can check the name of the passed object's class type and write conditional handling based on that.

class A:
   def __init__(self, arg)
      # Get the Argument's class type as a String
      argClass = arg.__class__.__name__

      if argClass == 'foo':
         print 'Arg is of type "foo"'
         ...
      elif argClass == 'bar':
         print 'Arg is of type "bar"'
         ...
      else
         print 'Arg is of a different type'
         ...

This concept can be applied to multiple different scenarios through different methods as needed.

S. Gamgee
  • 501
  • 5
  • 16
7

In Python, you'd do this with a default argument.

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i
John Gaines Jr.
  • 11,174
  • 1
  • 25
  • 25
7

python 3.5 added the typing module. This included an overload decorator.

This decorator's intended purpose it to help type checkers. Functionally its just duck typing.

from typing import Optional, overload


@overload
def foo(index: int) -> str:
    ...


@overload
def foo(name: str) -> str:
    ...


@overload
def foo(name: str, index: int) -> str:
    ...


def foo(name: Optional[str] = None, index: Optional[int] = None) -> str:
    return f"name: {name}, index: {index}"


foo(1)
foo("bar", 1)
foo("bar", None)

This leads to the following type information in vs code:

Results in vscode

And while this can help, note that this adds lots of "weird" new syntax. Its purpose - purely type hints - is not immediately obvious.

Going with Union of types usually is a better option.

felix-ht
  • 1,697
  • 15
  • 16
6

Python does not support method overloading like Java or C++. We may overload the methods, but we can only use the latest defined method.

# First sum method.
# Takes two argument and print their sum
def sum(a, b):
    s = a + b
    print(s)

# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
    s = a + b + c
    print(s)

# Uncommenting the below line shows an error
# sum(4, 5)

# This line will call the second sum method
sum(4, 5, 5)

We need to provide optional arguments or *args in order to provide a different number of arguments on calling.

Courtesy Python | Method Overloading

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Atihska
  • 4,803
  • 10
  • 56
  • 98
  • 1
    This is not overloading. It's called overwriting. The later one is supported by Python. The first can be implemented with decorators. – Paebbels Jan 01 '20 at 09:35
5

I just came across overloading.py (function overloading for Python 3) for anybody who may be interested.

From the linked repository's README file:

overloading is a module that provides function dispatching based on the types and number of runtime arguments.

When an overloaded function is invoked, the dispatcher compares the supplied arguments to available function signatures and calls the implementation that provides the most accurate match.

Features

Function validation upon registration and detailed resolution rules guarantee a unique, well-defined outcome at runtime. Implements function resolution caching for great performance. Supports optional parameters (default values) in function signatures. Evaluates both positional and keyword arguments when resolving the best match. Supports fallback functions and execution of shared code. Supports argument polymorphism. Supports classes and inheritance, including classmethods and staticmethods.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark Lawrence
  • 718
  • 8
  • 7
4

Python 3.x includes standard typing library which allows for method overloading with the use of @overload decorator. Unfortunately, this is to make the code more readable, as the @overload decorated methods will need to be followed by a non-decorated method that handles different arguments. More can be found here here but for your example:

from typing import overload
from typing import Any, Optional
class A(object):
    @overload
    def stackoverflow(self) -> None:    
        print('first method')
    @overload
    def stackoverflow(self, i: Any) -> None:
        print('second method', i)
    def stackoverflow(self, i: Optional[Any] = None) -> None:
        if not i:
            print('first method')
        else:
            print('second method', i)

ob=A()
ob.stackoverflow(2)
nickyfot
  • 1,932
  • 17
  • 25
  • 1
    The "The" at the end of your answer makes me think that you haven't finished writing your answer. Please [edit] your answer to complete it. – Artjom B. Oct 10 '18 at 15:47
2

In the MathMethod.py file:

from multipledispatch import dispatch
@dispatch(int, int)
def Add(a, b):
   return a + b 
@dispatch(int, int, int)  
def Add(a, b, c):
   return a + b + c 
@dispatch(int, int, int, int)    
def Add(a, b, c, d):
   return a + b + c + d

In the Main.py file

import MathMethod as MM 
print(MM.Add(200, 1000, 1000, 200))

We can overload the method by using multipledispatch.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mahabubuzzaman
  • 349
  • 3
  • 3
2

Python added the @overload decorator with PEP-3124 to provide syntactic sugar for overloading via type inspection - instead of just working with overwriting.

Code example on overloading via @overload from PEP-3124

from overloading import overload
from collections import Iterable

def flatten(ob):
    """Flatten an object to its component iterables"""
    yield ob

@overload
def flatten(ob: Iterable):
    for o in ob:
        for ob in flatten(o):
            yield ob

@overload
def flatten(ob: basestring):
    yield ob

is transformed by the @overload-decorator to:

def flatten(ob):
    if isinstance(ob, basestring) or not isinstance(ob, Iterable):
        yield ob
    else:
        for o in ob:
            for ob in flatten(o):
                yield ob
Nex
  • 421
  • 1
  • 4
  • 17
  • Something like this would be really great, but this is just a proposal in the PEP-3124, which is in "deferred" state. It is not implemented and not available yet in any version of Python. – Victor Schröder Jan 07 '22 at 21:37
2

There are some libraries that make this easy:

functools - if you only need the first argument use @singledispatch

plum-dispatch - feature rich method/function overloading.

multipledispatch - alternative to plum less features but lightweight.

BenedictWilkins
  • 1,173
  • 8
  • 25