How to annotate types of multiple return values?

125,595

You are always returning one object; using return one, two simply returns a tuple.

So yes, -> Tuple[bool, str] is entirely correct.

Only the Tuple type lets you specify a fixed number of elements, each with a distinct type. You really should be returning a tuple, always, if your function produces a fixed number of return values, especially when those values are specific, distinct types.

Other sequence types are expected to have one type specification for a variable number of elements, so typing.Sequence is not suitable here. Also see What's the difference between lists and tuples?

Tuples are heterogeneous data structures (i.e., their entries have different meanings), while lists are homogeneous sequences. Tuples have structure, lists have order.

Python's type hint system adheres to that philosophy, there is currently no syntax to specify an iterable of fixed length and containing specific types at specific positions.

If you must specify that any iterable will do, then the best you can do is:

-> Iterable[Union[bool, str]]

at which point the caller can expect booleans and strings in any order, and of unknown length (anywhere between 0 and infinity).

Last but not least, as of Python 3.9, you can use

-> tuple[bool, str]

instead of -> Tuple[bool, str]; support for type hinting notation has been added to most standard-library container types (see PEP 585 for the complete list). In fact, you can use this as of Python 3.7 too provided you use the from __future__ import annotations compiler switch for your modules and a type checker that supports the syntax.

Share:
125,595

Related videos on Youtube

Richard Hansen
Author by

Richard Hansen

Updated on October 07, 2021

Comments

  • Richard Hansen
    Richard Hansen over 2 years

    How do I use type hints to annotate a function that returns an Iterable that always yields two values: a bool and a str? The hint Tuple[bool, str] is close, except that it limits the return value type to a tuple, not a generator or other type of iterable.

    I'm mostly curious because I would like to annotate a function foo() that is used to return multiple values like this:

    always_a_bool, always_a_str = foo()
    

    Usually functions like foo() do something like return a, b (which returns a tuple), but I would like the type hint to be flexible enough to replace the returned tuple with a generator or list or something else.

  • Richard Hansen
    Richard Hansen over 7 years
    The language specification allows returning other iterables; foo() could do yield True; yield "blah" and a, b = foo() would still work. Or foo() could return a list. I reworded my question to make it clear that I'm interested in hinting an arbitrary iterable, not a tuple.
  • Martijn Pieters
    Martijn Pieters over 7 years
    @RichardHansen: that may well be, but type hinting only provides you with Tuple to express a heterogenous, fixed length return value.
  • Martijn Pieters
    Martijn Pieters over 7 years
    @RichardHansen: if you want to return a list, then that's fine, but there is no facility to express that the list will have a fixed length and that specific elements in that list have specific values.
  • Richard Hansen
    Richard Hansen over 7 years
    "What you want is not possible" is a good answer, assuming it's correct. :)
  • Martijn Pieters
    Martijn Pieters over 7 years
    @RichardHansen: I've re-checked the PEPs and documentation of typing and mypy another 2 times since posting; I'm pretty confident I didn't miss anything. That said, there are several regulars here on SO with plenty of Python type hinting experience that won't hesitate to correct me if turn out to be wrong, or will post a better answer.
  • Ignatius
    Ignatius about 3 years
    Since Python 3.9, typing.Tuple is deprecated and the built-in tuple now supports type annotation with [], so you can write -> tuple[bool str]. docs.python.org/3.9/library/typing.html#typing.Tuple
  • Joel
    Joel almost 3 years
    In order to run this code in python 3.8 you may have to add from typing import Tuple, List
  • Martijn Pieters
    Martijn Pieters almost 3 years
    @Joel: that applies to any Python 3 version; the from typing import ... is implied.
  • sorin
    sorin over 2 years
    And how about naming the returned tuple values in order to document them? Many functions do return or yield multiple values and we need to also document their meaning. Can can we put a name for each of them?
  • Martijn Pieters
    Martijn Pieters over 2 years
    @sorin use a NamedTuple.
  • matanster
    matanster over 2 years
    I wonder if there is also syntax for type hinting the values in the caller site, i.e. type hinting a and b in: a, b = fn()
  • Martijn Pieters
    Martijn Pieters over 2 years
    @matanster: not when assigning to multiple variables; you can annotate when there is a single variable: res: tuple[typea, typeb] = fn(). Unpack on a separate line: a, b = res. Or create separate type declarations first.
  • william_grisaitis
    william_grisaitis about 2 years
    @Martijn Pieters why is from typing implied? since we can use getitem on built-in types, it seems like it's not necessary anymore (e.g. tuple[this, that]). is this wrong? maybe it's still required in some instances?
  • Martijn Pieters
    Martijn Pieters about 2 years
    @william_grisaitis: no, if you are not using the typing.Tuple object then you don't need to import it.