0

I want to implement function overloading in Python. I know by default Python does not support overloading. That is what I am asking this question.

I have the following code:

def parse():
    results = doSomething()  
    return results 
x = namedtuple('x',"a b c")

def parse(query: str, data: list[x]):
    results = doSomethingElse(query, data)
    return results

The only solution I can think of is to check the arguments:

def parse(query: str, data: list[x]):
    if query is None and data is None:
       results = doSomething()  
       return results 
    else:
       results = doSomethingElse(query, data)   
       return results

Is it possible to do function overloading in Python like in Java (i.e. with out the branching)?

Is there is a clear way using a decorator or some library?

Daniil Fajnberg
  • 12,753
  • 2
  • 10
  • 41
Exploring
  • 2,493
  • 11
  • 56
  • 97
  • Python does not support overloading. – juanpa.arrivillaga Dec 01 '22 at 05:58
  • Does this answer your question? [How do I use method overloading in Python?](https://stackoverflow.com/questions/10202938/how-do-i-use-method-overloading-in-python) – Abirbhav G. Dec 01 '22 at 05:58
  • There's no overloading in Python. You could fiddle something together with decorators but in general: if you learn a new language use it as it is intended to use. Don't try to use it like the languages you already know. – Klaus D. Dec 01 '22 at 06:01
  • 1
    However, there are libraries, e.g. `multimethod` that hide the branching for you – juanpa.arrivillaga Dec 01 '22 at 06:02
  • What you already have is the second-best way to do it. The best way to do it is: don't. – hobbs Dec 01 '22 at 06:05
  • In most cases, overloading is an attempt to gloss over the fact that you should have defined two separate functions in the first place. The programmer who has to decide which arguments to pass to `parse` could just as easily decide whether to call `parse_nothing()` or `pass_something("foo", [1,2,3])` instead. – chepner Dec 01 '22 at 13:24

1 Answers1

2

There is the typing.overload decorator used for properly annotating a callable with two or more distinct call signatures. But it still requires exactly one actual implementation. The usage would be as follows:

from typing import overload


@overload
def parse(query: None = None, data: None = None) -> None:
    ...


@overload
def parse(query: str, data: list[object]) -> None:
    ...


def parse(query: str | None = None, data: list[object] | None = None) -> None:
    if query is None and data is None:
        print("something")
    else:
        print(f"something else with {query=} and {data=}")


parse()            # something
parse("foo", [1])  # something else with query='foo' and data=[1]

Note that the ellipses ... are meant literally, i.e. that is all that should be in the "body" of that function overload.

That is how it is done in Python. As mentioned in the comments already, there is no syntax for literally writing overloaded function implementations. If you write two implementations, the last one will simply override the first.

Even if you could build something like that with syntactically pleasing decorators, I would probably advise against it because it will likely confuse everyone else since it is not how Python was designed. Also, if you have a lot of complex overloads that all require different implementation logic, I would argue this is probably just bad design. And if the branches are clear/simple as in your example, then I see no problem with having them in one function body.

Daniil Fajnberg
  • 12,753
  • 2
  • 10
  • 41