The typing module

So far, we’ve added type hints that use only basic concrete types likestr and float. What if we want to express more complex types,such as “a list of strings” or “an iterable of ints”?

You can find many of these more complex static types inside of the typingmodule. For example, to indicate that some function can accept a list ofstrings, use the List type:

  1. from typing import List
  2.  
  3. def greet_all(names: List[str]) -> None:
  4. for name in names:
  5. print('Hello ' + name)
  6.  
  7. names = ["Alice", "Bob", "Charlie"]
  8. ages = [10, 20, 30]
  9.  
  10. greet_all(names) # Ok!
  11. greet_all(ages) # Error due to incompatible types

The List type is an example of something called a generic type: it canaccept one or more type parameters. In this case, we parameterized Listby writing List[str]. This lets mypy know that greet_all accepts specificallylists containing strings, and not lists containing ints or any other type.

In this particular case, the type signature is perhaps a little too rigid.After all, there’s no reason why this function must accept specifically a list –it would run just fine if you were to pass in a tuple, a set, or any other custom iterable.

You can express this idea using the Iterable type instead of List:

  1. from typing import Iterable
  2.  
  3. def greet_all(names: Iterable[str]) -> None:
  4. for name in names:
  5. print('Hello ' + name)

As another example, suppose you want to write a function that can accept _either_ints or strings, but no other types. You can express this using the Union type:

  1. from typing import Union
  2.  
  3. def normalize_id(user_id: Union[int, str]) -> str:
  4. if isinstance(user_id, int):
  5. return 'user-{}'.format(100000 + user_id)
  6. else:
  7. return user_id

Similarly, suppose that you want the function to accept only strings or None. You canagain use Union and use Union[str, None] – or alternatively, use the typeOptional[str]. These two types are identical and interchangeable: Optional[str]is just a shorthand or alias for Union[str, None]. It exists mostly as a convenienceto help function signatures look a little cleaner:

  1. from typing import Optional
  2.  
  3. def greeting(name: Optional[str] = None) -> str:
  4. # Optional[str] means the same thing as Union[str, None]
  5. if name is None:
  6. name = 'stranger'
  7. return 'Hello, ' + name

The typing module contains many other useful types. You can find aquick overview by looking through the mypy cheatsheetsand a more detailed overview (including information on how to make your owngeneric types or your own type aliases) by looking through thetype system reference.

One final note: when adding types, the convention is to import typesusing the form from typing import Iterable (as opposed to doingjust import typing or import typing as t or from typing import *).

For brevity, we often omit these typing imports in code examples, butmypy will give an error if you use types such as Iterablewithout first importing them.