2.1. Type Annotation

Types are not required, and never will be. -- Guido van Rossum, Python initiator, core developer, former BDFL

It should be emphasized that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention. -- Python Software Foundation

2.1.1. Rationale

2.1.2. Int

>>> data: int = 0
>>> data: int = 1
>>> data: int = -1

2.1.3. Float

>>> data: float = 0.0
>>> data: float = 1.23
>>> data: float = -1.23

2.1.4. Str

>>> data: str = ''
>>> data: str = 'Jan Twardowski'

2.1.5. Bool

>>> data: bool = True
>>> data: bool = False

2.1.6. Union

>>> from typing import Union
>>>
>>> number: Union[int, float] = 1337
>>> number: Union[int, float] = 1.337

Since Python 3.10: PEP 604 -- Allow writing union types as X | Y

>>> number: int|float = 1337        # doctest: +SKIP
>>> number: int|float = 1.337       # doctest: +SKIP
>>> number: int|None = 1337         # doctest: +SKIP
>>> number: int|None = None         # doctest: +SKIP

Result of this expression would then be valid in isinstance() and issubclass()

>>> isinstance(1337, int|float)     # doctest: +SKIP
>>> isinstance(1337, int|None)      # doctest: +SKIP

2.1.7. Optional

>>> from typing import Optional
>>>
>>> data: Optional[int] = 1337
>>> data: Optional[int] = None
>>> from typing import Optional
>>>
>>> firstname: str = 'Melissa'
>>> lastname: str = 'Lewis'
>>> age: Optional[float] = None

Since Python 3.10: PEP 645 -- Allow writing optional types as x?

>>> age: int? = 1337                # doctest: +SKIP
>>> age: int? = None                # doctest: +SKIP

Result of this expression would then be valid in isinstance() and issubclass()

>>> isinstance(1337, int?)          # doctest: +SKIP

2.1.8. Aliases

>>> from typing import Union
>>>
>>> Number = Union[float, int]
>>> age: Number = 10
>>> age: Number = 10.5

Since Python 3.10 PEP 613 -- TypeAlias Annotation

PEP 484 introduced the concept of type aliases, only requiring them to be top-level unannotated assignments. This simplicity sometimes made it difficult for type checkers to distinguish between type aliases and ordinary assignments, especially when forward references or invalid types were involved. Compare:

>>> StrCache = 'Cache[str]'  # a type alias                 # doctest: +SKIP
>>> LOG_PREFIX = 'LOG[DEBUG]'  # a module constant          # doctest: +SKIP

Now the typing module has a special annotation TypeAlias to declare type aliases more explicitly:

>>> StrCache: TypeAlias = 'Cache[str]'  # a type alias      # doctest: +SKIP
>>> LOG_PREFIX = 'LOG[DEBUG]'  # a module constant          # doctest: +SKIP

2.1.9. Final

Since Python 3.8: PEP 591 -- Adding a final qualifier to typing

>>> from typing import Final
>>>
>>> m: Final[int] = 1
>>> km: Final[int] = 1000 * m
>>> from typing import Final
>>>
>>> second: Final[int] = 1
>>> minute: Final[int] = 60 * second
>>> hour: Final[int] = 60 * minute
>>> day: Final[int] = 24 * hour

2.1.10. Types are not Enforced

  • This code will run without any problems

  • Although mypy or pyre-check will throw error

>>> name: int = 'Jan Twardowski'
>>> age: float = 30
>>> is_adult: int = True