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 typing
module. For example, to indicate that some function can accept a list ofstrings, use the List
type:
- from typing import List
- def greet_all(names: List[str]) -> None:
- for name in names:
- print('Hello ' + name)
- names = ["Alice", "Bob", "Charlie"]
- ages = [10, 20, 30]
- greet_all(names) # Ok!
- 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 List
by 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
:
- from typing import Iterable
- def greet_all(names: Iterable[str]) -> None:
- for name in names:
- 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:
- from typing import Union
- def normalize_id(user_id: Union[int, str]) -> str:
- if isinstance(user_id, int):
- return 'user-{}'.format(100000 + user_id)
- else:
- 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:
- from typing import Optional
- def greeting(name: Optional[str] = None) -> str:
- # Optional[str] means the same thing as Union[str, None]
- if name is None:
- name = 'stranger'
- 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 Iterable
without first importing them.