-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Docs: show how to @overload function annotations in user code #2792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,63 @@ | ||
Function overloading in stubs | ||
============================= | ||
Function Overloading | ||
==================== | ||
|
||
Sometimes you have a library function that seems to call for two or | ||
more signatures. That's okay -- you can define multiple *overloaded* | ||
instances of a function with the same name but different signatures in | ||
a stub file (this feature is not supported for user code, at least not | ||
yet) using the ``@overload`` decorator. For example, we can define an | ||
``abs`` function that works for both ``int`` and ``float`` arguments: | ||
Sometimes the types in a function depend on each other in ways that can't be | ||
captured with a simple ``Union``. For example, the ``__getitem__`` (``[]`` bracket | ||
indexing) method can take an integer and return a single item, or take a ``slice`` | ||
and return a ``Sequence`` of items. You might be tempted to annotate it like so: | ||
|
||
.. code-block:: python | ||
|
||
# This is a stub file! | ||
class Seq(Generic[T], Sequence[T]): | ||
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]: | ||
pass | ||
|
||
But this is a little loose, as it implies that when you put in an ``int`` you might | ||
sometimes get out a single item or sometimes a sequence. To capture a constraint | ||
such as a return type that depends on a parameter type, we can use | ||
`overloading <https://www.python.org/dev/peps/pep-0484/#function-method-overloading>`_ | ||
to give the same function multiple type annotations (signatures). | ||
|
||
from typing import overload | ||
|
||
@overload | ||
def abs(n: int) -> int: pass | ||
|
||
@overload | ||
def abs(n: float) -> float: pass | ||
.. code-block:: python | ||
|
||
Note that we can't use ``Union[int, float]`` as the argument type, | ||
since this wouldn't allow us to express that the return | ||
type depends on the argument type. | ||
from typing import Generic, Sequence, overload | ||
T = TypeVar('T') | ||
|
||
Now if we import ``abs`` as defined in the above library stub, we can | ||
write code like this, and the types are inferred correctly: | ||
class Seq(Generic[T], Sequence[T]): | ||
@overload # These are just for the type checker, and overwritten by the real implementation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Such long comments will look a bit ugly on |
||
def __getitem__(self, index: int) -> T: | ||
pass | ||
|
||
.. code-block:: python | ||
@overload # All overloads and the implementation must be adjacent in the source file, and overload order may matter | ||
def __getitem__(self, index: slice) -> Sequence[T]: | ||
pass | ||
|
||
n = abs(-2) # 2 (int) | ||
f = abs(-1.5) # 1.5 (float) | ||
def __getitem__(self, index): # Actual implementation goes last, and does *not* get type hints or @overload decorator | ||
if isinstance(index, int): | ||
... | ||
elif isinstance(index, slice): | ||
... | ||
|
||
Overloaded function variants are still ordinary Python functions and | ||
they still define a single runtime object. The following code is | ||
thus valid: | ||
|
||
.. code-block:: python | ||
|
||
my_abs = abs | ||
my_abs(-2) # 2 (int) | ||
my_abs(-1.5) # 1.5 (float) | ||
they still define a single runtime object. There is no multiple dispatch | ||
happening, and you must manually handle the different types (usually with | ||
:func:`isinstance` checks). | ||
|
||
The overload variants must be adjacent in the code. This makes code | ||
clearer, as you don't have to hunt for overload variants across the | ||
file. | ||
|
||
Overloads in stub files are exactly the same, except of course there is no | ||
implementation. | ||
|
||
.. note:: | ||
|
||
As generic type variables are erased at runtime when constructing | ||
instances of generic types, an overloaded function cannot have | ||
variants that only differ in a generic type argument, | ||
e.g. ``List[int]`` versus ``List[str]``. | ||
e.g. ``List[int]`` and ``List[str]``. | ||
|
||
.. note:: | ||
|
||
If you are writing a regular module rather than a stub, you can | ||
often use a type variable with a value restriction to represent | ||
functions as ``abs`` above (see :ref:`type-variable-value-restriction`). | ||
If you just need to constrain a type variable to certain types or subtypes, | ||
you can use a :ref:`value restriction <type-variable-value-restriction>`). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic[T]
here and below are redundant.