Overloaded functions in Python

102,002

Solution 1

EDIT For the new single dispatch generic functions in Python 3.4, see http://www.python.org/dev/peps/pep-0443/

You generally don't need to overload functions in Python. Python is dynamically typed, and supports optional arguments to functions.

def myfunction(first, second, third = None):
    if third is None:
        #just use first and second
    else:
        #use all three

myfunction(1, 2) # third will be None, so enter the 'if' clause
myfunction(3, 4, 5) # third isn't None, it's 5, so enter the 'else' clause

Solution 2

In normal Python you can't do what you want. There are two close approximations:

def myfunction(first, second, *args):
    # 'args' is a tuple of extra arguments

def myfunction(first, second, third=None):
    # 'third' is optional

However, if you really want to do this, you can certainly make it work (at the risk of offending the traditionalists ;o). In short, you would write a wrapper(*args) function that checks the number of arguments and delegates as appropriate. This kind of "hack" is usually done via decorators. In this case, you could achieve something like:

from typing import overload

@overload
def myfunction(first):
    ....

@myfunction.overload
def myfunction(first, second):
    ....

@myfunction.overload
def myfunction(first, second, third):
    ....

And you'd implement this by making the overload(first_fn) function (or constructor) return a callable object where the __call__(*args) method does the delegation explained above and the overload(another_fn) method adds extra functions that can be delegated to.

You can see an example of something similar here http://acooke.org/pytyp/pytyp.spec.dispatch.html, but that is overloading methods by type. It's a very similar approach...

And something similar (using argument types) is being added to Python 3 - PEP 443 -- Single-dispatch generic functions

Solution 3

Yes, it's possible. I wrote the code below in Python 3.2.1:

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

Usage:

myfunction=overload(no_arg_func, one_arg_func, two_arg_func)

Note that the lambda returned by the overload functions choose a function to call depending on the number of unnamed arguments.

The solution isn't perfect, but at the moment I can't write anything better.

Solution 4

It is not possible directly. You can use explicit type checks on the arguments given though, although this is generally frowned upon.

Python is dynamic. If you are unsure what an object can do, just try: and call a method on it, then except: errors.

If you don't need to overload based on types, but just on the number of arguments, use keyword arguments.

Share:
102,002
Trcx
Author by

Trcx

Updated on July 08, 2022

Comments

  • Trcx
    Trcx almost 2 years

    Is it possible to have overloaded functions in Python?

    In C# I would do something like

    void myfunction (int first, string second)
    {
        # Some code
    }
    
    void myfunction (int first, string second, float third)
    {
        # Some different code
    }
    

    And then when I call the function it would differentiate between the two based on the number of arguments. Is it possible to do something similar in Python?

  • agf
    agf almost 13 years
    I don't think he knew about optional arguments.
  • Peter.Ladanyi
    Peter.Ladanyi almost 13 years
    But note that calling different functions based on the type of the arguments is much more difficult (although not impossible).
  • Val
    Val over 10 years
    Well, there is a difference between overloading/polymorphism and conditionals. Do you mean that we do not need the polymorphysm since we have the conditionals?
  • agf
    agf over 10 years
    @Val I'm saying, basically, that in a dynamically typed language you don't need overloading as a language feature because you can trivially emulate it in code, and so can get polymorphism that way.
  • Val
    Val over 10 years
    I do not see how dynamic linking answers my question. Now, since java is statically typed, you say that in cannot have the optional arguments. I do not understand this also.
  • agf
    agf over 10 years
    @Val I'm saying that between optional arguments and dynamic types the way you have them in Python, you don't need Java style method overloading to achieve polymorphism.
  • navidoo
    navidoo over 9 years
    What if I want one version of the method to return a generator, and the other version "return" a single object, depending on the parameters? Yielding and returning from the same method is not permitted in python 2.x.
  • agf
    agf over 9 years
    @navidoo I would argue that isn't a good idea -- a function shoudn't return completely different types of things. However, you can always define a local generator function inside the main function, call it, and return the resulting generator -- from the outside it will be the same as if the main function was a generator. Example here.
  • goul
    goul about 7 years
    @agf What about the case where you need def searchItem(self, item_key) and searchItem(self, item_description)?
  • agf
    agf about 7 years
    @goul Generally, this is what keyword arguments are for. def search_item(self, item_key = None, item_description = None). On Python 3, you can make them keyword only to avoid the confusion of them being specified positionally -- def search_item(self, *, item_key = None, item_description = None). There are also many other ways to solve this type of problem, like having two subclasses to handle the different cases, just two different methods, etc. It depends on the structure of the rest of the code.
  • CptJero
    CptJero about 5 years
    The range builtin uses overload, so is it really a hack? github.com/python/typeshed/blob/master/stdlib/2and3/…
  • Peter Mortensen
    Peter Mortensen over 3 years
    Probably not accelaration. More like acceleration (an ae).