Python Function Overloading

Overloaded functions in Python

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

Python function overloading recommended approach

After some research, and taking inspirations from the @Copperfield answer, I found an elegant solution to the problem.

Let's first rephrase the problem - we have a function that takes an object. We want to provide some overloads, which will do the validations/ conversions etc. and call the base function which accepts object. We also need to reject any call not following any function signature which are not implemented.

The library that I found very useful was multipledispatch. An easy example:

from multipledispatch import dispatch

@dispatch(int, int)
def add_nums(num1: int, num2: int) -> int:
return num1 + num2

@dispatch(str, str)
def add_nums(num1: str, num2: str) -> int:
# do some useful validations/ object transformations
# implement any intermediate logic before calling the base func
# this enables base function do it's intended feature rather than
# implementing overloads
return add_nums(int(num1), int(num2))

if we call add_nums(40, 15), we get 55 as the (int, int) version get called. add_nums('10', '15') get us 25 as expected as (str, str) version get called.

It becomes very interesting when we call add_nuns(10, 10.0) as this will fail saying NotImplementedError: Could not find signature for add_nums: <int, float>. Essentially any call not in (int, int) or (str, str) format, fail with NotImplementedError exception.

This is by far the closest behaviour of function overloading, when comparing with typed languages.

The only concern I have - this library was last updated on Aug 9, 2018.

Function overloading in Python: Missing

As unwind noted, keyword arguments with default values can go a long way.

I'll also state that in my opinion, it goes against the spirit of Python to worry a lot about what types are passed into methods. In Python, I think it's more accepted to use duck typing -- asking what an object can do, rather than what it is.

Thus, if your method may accept a string or a tuple, you might do something like this:

def print_names(names):
"""Takes a space-delimited string or an iterable"""
try:
for name in names.split(): # string case
print name
except AttributeError:
for name in names:
print name

Then you could do either of these:

print_names("Ryan Billy")
print_names(("Ryan", "Billy"))

Although an API like that sometimes indicates a design problem.

python static overloading of member function

You aren't overloading the method; you are replacing it with the static method. You'll have to pick a different name for the static method.

type function overloading in python

type() isn't using overloading. It is using the C-code equivalent of *args to alter behaviour based on how many arguments you passed in. If you are interested in the specifics, see the type_new function:

/* Special case: type(x) should return x->ob_type */
{
const Py_ssize_t nargs = PyTuple_GET_SIZE(args);
const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds);

if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) {
PyObject *x = PyTuple_GET_ITEM(args, 0);
Py_INCREF(Py_TYPE(x));
return (PyObject *) Py_TYPE(x);
}

which essentially tests if len(args) == 1 and not kwargs, as well as making sure the first argument is the type object itself and not a subclass.

You could do something similar with your Dog.Print() method; if args is not empty assume it was called with name, age instead of just age:

def Print(self, age, *args):
if args:
name, age = args + (age,)
else:
name = None
if name is not None:
print(name)
print(age)

although that would make it a terribly bad API. It is better to add optional arguments to the end:

def Print(self, age, name=None):
if name is not None:
print(name)
print(age)

as that reduces confusion and is easier to remember.

Pythonic function overloading?

Don't use overloading. Where the problem that you're trying to solve is "about ~80% of the code in each function is repeated", the better solution is to factor out that code into its own function, call it _set_delay for example, then call it from each of the set_delay_* functions.

To me, overloading only makes sense where the parameters overlap, but none do in your case. For contrast, say I write range(10) but then I realize I want to start from 1; thanks to overloading, I can simply change it to range(1, 10). Meanwhile, if I added an argument to your proposed set_delay, I would get totally different behaviour.



Related Topics



Leave a reply



Submit