pythonpython-3.xiterable-unpackingpython-typing

typing: type hinting when function returns tuple with unpacked list


I have this:

from typing import Tuple
import random

a = random.randint(100) # some random number

def foo(a: int) -> Tuple:
    b = []
    for _ in random.randint(0, 10):
       b.append(random.randint(-5, 5) # adding random numbers to b
    return a, *b

And I want to write return type for this function, but I don't now how to do this properly:

I tried this:

from typing import Tuple
import random

a = random.randint(100) # some random number. It doesn't matter

def foo(a: int) -> Tuple[int, *Tuple[int, ...]]:
    b = []
    for _ in random.randint(0, 10):
       b.append(random.randint(-5, 5) # adding random numbers to b
    return a, *b

Pycharm with mypy says: foo(a: int) -> Tuple[int, Any] But I need the function to return the type of variable that was passed to it

In a real project, it takes a generic and returns a tuple with the object and the unpacked list in it for readability

Real function:

...
    def get_entities_with(self, *component_types):
        for entity in self.entities.values():
            require_components = [component for component in entity.components if type(component) in component_types]
            if len(require_components) == len(component_types):
                yield entity, *require_components
...

.pyi File:

T = TypeVar("T")
...
    def get_entities_with(self, *components:Type[T]) -> Generator[Entity, *Tuple[T, ...]]: ...

Solution

  • If you are using Python 3.11 or above, you can simply use the unpack asterisk (*) in the type hint for the return type, similar to the way you wrote it in your question (but slightly different, see example below).

    But since, as of the time of writing, Python 3.11 is still not public your are likely using a version 3.10 or earlier. If this is the case you can use the backported special type Unpack, that is available in typing_extensions, available on pypi.

    Example usage:

    from typing_extensions import Unpack
    
    # Python <=3.10
    def unpack_hints_py_10_and_below(args: list[str]) -> tuple[int, Unpack[str]]:
        first_arg, *rest = args
        return len(first_arg), *rest
    
    # Python >= 3.11
    def unpack_hints_py_11_and_above(args: list[str]) -> tuple[int, *str]:
        first_arg, *rest = args
        return len(first_arg), *rest
    

    Further (heavy) Reading: see PEP 646.

    Happy typing!