>>> 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?
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.
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.
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.
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.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With