How to specify multiple return types using type-hints

191,644

Solution 1

From the documentation

class typing.Union

Union type; Union[X, Y] means either X or Y.

Hence the proper way to represent more than one return data type is

from typing import Union


def foo(client_id: str) -> Union[list,bool]

But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."

>>> def foo(a:str) -> list:
...     return("Works")
... 
>>> foo(1)
'Works'

As you can see I am passing a int value and returning a str. However the __annotations__ will be set to the respective values.

>>> foo.__annotations__ 
{'return': <class 'list'>, 'a': <class 'str'>}

Please Go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??

Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.


From Python 3.10 onwards, there is a new way to represent this union. See Union Type:

A union object holds the value of the | (bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared to typing.Union.

As we can see, this is exactly the same as typing.Union in the previous versions. Our previous example can be modified to use this notation:

def foo(client_id: str) -> list | bool:

Solution 2

In case anyone landed here in search of "how to specify types of multiple return values?", use Tuple[type_value1, ..., type_valueN]

from typing import Tuple

def f() -> Tuple[dict, str]:
    a = {1: 2}
    b = "hello"
    return a, b

More info: How to annotate types of multiple return values?

Solution 3

The statement def foo(client_id: str) -> list or bool: when evaluated is equivalent to def foo(client_id: str) -> list: and will therefore not do what you want.

The native way to describe a "either A or B" type hint is Union (thanks to Bhargav Rao):

def foo(client_id: str) -> Union[list, bool]:

Or, starting with Python 3.10 and beyond, using the | operator:

def foo(client_id: str) -> list | bool:

I do not want to be the "Why do you want to do this anyway" guy, but maybe having 2 return types isn't what you want:

If you want to return a bool to indicate some type of special error-case, consider using Exceptions instead. If you want to return a bool as some special value, maybe an empty list would be a good representation. You can also indicate that None could be returned with Optional[list]

Solution 4

Python 3.10 (use |): Example for a function which takes a single argument that is either an int or str and returns either an int or str:

def func(arg: int | str) -> int | str:
              ^^^^^^^^^     ^^^^^^^^^ 
             type of arg   return type

Python 3.5 - 3.9 (use typing.Union):

from typing import Union
def func(arg: Union[int, str]) -> Union[int, str]:
              ^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^ 
                type of arg         return type

For the special case of X | None you can use Optional[X].

Share:
191,644
Yahya Uddin
Author by

Yahya Uddin

CTO &amp; Leader Developer of The Dealer App, with a Computer Science degree from University of Warwick (UK).

Updated on July 08, 2022

Comments

  • Yahya Uddin
    Yahya Uddin almost 2 years

    I have a function in python that can either return a bool or a list. Is there a way to specify the return types using type hints?

    For example, is this the correct way to do it?

    def foo(id) -> list or bool:
        ...
    
  • Nathaniel Ford
    Nathaniel Ford over 8 years
    There are uses where returning multiple types may be what you want: for instance if you need to return one of some set of subtypes, but not other subtypes, or if you are attempting to process data and want to return the raw form if processing isn't available. Also, if you are wrapping legacy code it can be quite useful, because it helps the upgrade process and/or see awkward places.
  • Yahya Uddin
    Yahya Uddin over 8 years
    Is there an equivalent in Python 3.4
  • Bhargav Rao
    Bhargav Rao over 8 years
    @YahyaUddin Nope - PEP 484 :'( .... It's only for Python3.5 upwards.
  • Yahya Uddin
    Yahya Uddin over 8 years
    But I know type hints still work for Python 3.4 as well i.e. def foo(id: str). Isn't this also type hints?
  • Bhargav Rao
    Bhargav Rao over 8 years
    @YahyaUddin Naw. They don't work in 3.4. Type hints are Python3.5 only. Did you check you python version correctly?
  • Yahya Uddin
    Yahya Uddin over 8 years
    The exceptions and empty list idea was helpful as well. thanks
  • Bhargav Rao
    Bhargav Rao over 8 years
    @YahyaUddin Quite surprising. Did you mean Function Annotations by any chance?
  • Yahya Uddin
    Yahya Uddin over 8 years
    So let me see if I got this. Python 3.4 has function annotations that dosen't do anything other than annotate that is NOT enforced. But in Python 3.5 this is actual type checking.
  • Bhargav Rao
    Bhargav Rao almost 7 years
    @Bobort, approved it, but note that those are meant to be posted as comments on the answer (and not an edit). This is because it'll be reviewed by the review-queue where users won't have any knowledge of the technology used (i.e they might be a C# or a Java programmer). Take care the next time.
  • Bobort
    Bobort almost 7 years
    @BhargavRao, sorry about that! I just felt it was too important to leave in the comments section.
  • Nico Villanueva
    Nico Villanueva over 3 years
    As per the docs, this is the correct way to do it (returning N types): docs.python.org/3/library/typing.html#typing.Tuple; whereas returning an Union should actually return ONE of N type values.
  • muxevola
    muxevola about 3 years
    The | operator doesn't work when I try to indicate I'm allowing my function to return both str and None (i.e. -> str | None). In this case, I get TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'. Union works properly, though.
  • Felk
    Felk almost 3 years
    as xjcl described in their answer, in case of "X or None" you can also use Optional[X]
  • jeffhale
    jeffhale over 2 years
    As of Python 3.9, you don't need to import the Tuple class from typing. Now it's just -> tuple[dict, str]
  • bballdave025
    bballdave025 over 2 years
    This answer, to me, is the most helpful and illuminating. It has basically all the other answers' information (except those answers or comments that suggest a non-multiple-type alternative) in a very concise form. Though the OP did not specifically ask about multiple argument types, the description of how to use them as well as multiple return types makes the answer much more complete. Though I give a single-typed example, I also appreciate that the answer removes any confusion (such as I had) as to specifically what was different (if anything) between foo( bar: int ) and foo( bar ) -> int
  • xjcl
    xjcl over 2 years
    Thanks for the praise (: I tried to give an answer that was short and visual
  • Stealth Rabbi
    Stealth Rabbi over 2 years
    this function doesn't specify any return type.
  • Or b
    Or b over 2 years
    And how do you do it when you have more than 2 possible types in the argument and not in function return?
  • Gabriel Caldas
    Gabriel Caldas about 2 years
    The question is actually about the return type, not the arguments' types
  • Stephen Ostermiller
    Stephen Ostermiller about 2 years
    A code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.