Python 中的重载函数

有没有可能在 Python 中使用重载函数?

在 C # 中,我会这样做

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


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

然后当我调用这个函数的时候它会根据参数的数量来区分这两个函数。有可能在 Python 中做类似的事情吗?

107207 次浏览

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

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.

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

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.

Overloading methods is tricky in Python. However, there could be usage of passing the dict, list or primitive variables.

I have tried something for my use cases, and this could help here to understand people to overload the methods.

Let's take the example use in one of the Stack Overflow questions:

A class overload method with call the methods from different class.

def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):

Pass the arguments from a remote class:

add_bullet(sprite = 'test', start=Yes, headto={'lat':10.6666, 'long':10.6666}, accelaration=10.6}

Or

add_bullet(sprite = 'test', start=Yes, headto={'lat':10.6666, 'long':10.6666}, speed=['10','20,'30']}

So, handling is being achieved for list, Dictionary or primitive variables from method overloading.

Try it out for your code.

Here is the way to overload python functions with default arguments as well as keyword arguments

from multipledispatch import dispatch


# FOR hi(a: int, b: int = 3)


@dispatch(int, int)
def _hi(a: int, b: int):
print(a, b)




@dispatch(int, int)
def hi(a: int, b: int = 3):
_hi(a, b)




@dispatch(int, b=int)
def hi(a: int, *, b: int = 3):
_hi(a, b)




# FOR hi(a: str, b: int = 3)


@dispatch(str, int)
def _hi(a: str, b: int):
print(a, b, 'str!')




@dispatch(str, int)
def hi(a: str, b: int = 3):
_hi(a, b)




@dispatch(str, b=int)
def hi(a: str, *, b: int = 3):
_hi(a, b)


hi(2)
hi(2, 3)
hi(2, b=3)
hi('2')
hi('2', 3)
hi('2', b=3)

Output

2 3
2 3
2 3
2 3 str!
2 3 str!
2 3 str!