How to annotate function that takes a tuple of variable length? (variadic tuple type annotation)

PythonPython 3.xType HintingMypyPython Typing

Python Problem Overview


I have a function that takes a tuple of different lengths as an argument:

from typing import Tuple


def process_tuple(t: Tuple[str]):
    # Do nasty tuple stuff

process_tuple(("a",))
process_tuple(("a", "b"))
process_tuple(("a", "b", "c"))

When I annotate function like mentioned above, I get these error messages

fool.py:9: error: Argument 1 to "process_tuple" has incompatible type "Tuple[str, str]"; expected "Tuple[str]"
fool.py:10: error: Argument 1 to "process_tuple" has incompatible type "Tuple[str, str, str]"; expected "Tuple[str]"

process_tuple really works with tuples and I use them as immutable lists of variable length. I haven't found any consensus on this topic on the internet, so I wonder how should I annotate this kind of input.

Python Solutions


Solution 1 - Python

We can annotate variable-length homogeneous tuples using the ... literal (aka Ellipsis) like this:

def process_tuple(t: Tuple[str, ...]):
    ...

or for Python3.9+

def process_tuple(t: tuple[str, ...]):
    ...

After that, the errors should go away.

From the docs:

> To specify a variable-length tuple of homogeneous type, use literal > ellipsis, e.g. Tuple[int, ...]. A plain Tuple is equivalent to > Tuple[Any, ...], and in turn to tuple.

Solution 2 - Python

In addition to the Ellipsis answer as posted by Azat you could make it more explicit by using @typing.overload or typing.Union

from typing import Tuple


@overload
def process_tuple(t: Tuple[str]):
    # Do nasty tuple stuff

@overload
def process_tuple(t: Tuple[str, str]):
    ...

Or with the Union:

from typing import Tuple, Union


def process_tuple(t: Union[Tuple[str], Tuple[str, str], Tuple[str, str, str]]):
    # Do nasty tuple stuff

Solution 3 - Python

Python 3.9+

Use tuple:

def process_tuple(t: tuple[str, ...]):
    pass

Since Python 3.9, typing.Tuple is depreciated. The documentation for typing.Tuple states:

> Deprecated since version 3.9: builtins.tuple now supports [].

Python 3.8 and earlier

If you are on Python 3.8 or earlier, you should still use typing.Tuple:

from typing import Tuple

def process_tuple(t: Tuple[str, ...]):
    pass

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMontrealView Question on Stackoverflow
Solution 1 - PythonAzat IbrakovView Answer on Stackoverflow
Solution 2 - PythonWolphView Answer on Stackoverflow
Solution 3 - PythonBrokenBenchmarkView Answer on Stackoverflow