Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload decorator in typings module doesn't seem to behave as expected

>>> from typing import overload

>>> @overload
... def hello(s: int):
...     return "Got an integer!"

>>> def hello(s: str):
...     return "Got a string"

Why does the calling hello(1) call the function with the string argument? Ideally, the @overload operator should handle it, right?

like image 505
saruftw Avatar asked Aug 27 '18 07:08

saruftw


People also ask

Why overloading is not supported in Python?

When the runtime encounters another function with the same name it updates the entry in the local namespace and thus removes the possibility of two functions co-existing. Hence python does not support Function overloading.

How does Python handle overloading?

Python does not support function overloading. Suppose we still want to use the feature of functional overloading. In that case, we can set the default values of parameters in the method as None, which won't give an error if that specific value is not passed as an argument while calling the function.

Does overloading work in Python?

Like other languages (for example, method overloading in C++) do, python does not support method overloading by default. But there are different ways to achieve method overloading in Python. The problem with method overloading in Python is that we may overload the methods but can only use the latest defined method.

What is overload decorator in Python?

The @overload decorator allows you to define alternate implementations of a function, specialized by argument type(s). A function with the same name must already exist in the local namespace.


1 Answers

Unfortunately, python does not allow function overloading. Each time you think you are overloading function, you are just overwriting previous function declaration. Quote from the docs:

The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method). The @overload-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-@overload-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a @overload-decorated function directly will raise NotImplementedError.

The correct usage of typing.overload is as follows:

from typing import overload


@overload
def hello(s: int) -> str:
    ...


@overload
def hello(s: str) -> str:
    ...


def hello(s):
    if isinstance(s, int):
        return "Got an integer!"
    if isinstance(s, str):
        return "Got a string"
    raise ValueError('You must pass either int or str')


if __name__ == '__main__':
    print(hello(1))

To show the actual benefit of typing.overload lets change def hello(s: int) to return int instead of str:

from typing import overload


@overload
def hello(s: int) -> int:
    ...


@overload
def hello(s: str) -> str:
    ...


def hello(s):
    if isinstance(s, int):
        return "Got an integer!"
    if isinstance(s, str):
        return "Got a string"
    raise ValueError('You must pass either int or str')


if __name__ == '__main__':
    print(hello(1))
    a = hello(1) + 1
    b = hello(1) + 'a'

Note, that the actual implementation still returns str - python does not perform any checks here. However, PyCharm raises a warning:

enter image description here

mypy also complains about invalid types:

➜ mypy test.py 
test.py:25: error: Unsupported operand types for + ("int" and "str")

The purpose of typing module is to allow third party tools to perform static checking of your code. There is no magic here - all types are ignored at runtime.

like image 187
awesoon Avatar answered Oct 21 '22 17:10

awesoon