3.1. Type Annotation Primitives

  • Also known as: "type annotations", "type hints", "gradual typing"

  • Types are not required, and never will be

  • Good IDE will give you hints

  • Types are used extensively in system libraries

  • More and more books and documentations use types

  • Introduced in Python 3.5

  • Since Python 3.5: PEP 484 -- Type Hints

  • Since Python 3.6: PEP 526 -- Syntax for Variable Annotations

  • Since Python 3.8: PEP 544 -- Protocols: Structural subtyping (static duck typing)

  • Since Python 3.9: PEP 585 -- Type Hinting Generics In Standard Collections

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

  • To type check use: mypy, pyre-check, pytypes

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

../../_images/typeannotation-timeline1.png

Figure 3.3. Timeline of changes to type annotations from Python 3.0 to now 1

3.1.1. Int

  • Used to inform static type checker that the variable should be int

Declaration:

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

Example:

>>> data: int
>>>
>>> data = 1        # ok
>>> data = -1       # ok
>>> data = 'hello'  # error

3.1.2. Float

  • Used to inform static type checker that the variable should be float

Declaration:

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

Example:

>>> data: float
>>>
>>> data = 1.0        # ok
>>> data = -1.0       # ok
>>> data = 'hello'    # error

3.1.3. Str

  • Used to inform static type checker that the variable should be str

Declaration:

>>> data: str
>>> data: str = ''
>>> data: str = 'hello'

Example:

>>> data: str
>>>
>>> data = 'Mark'           # ok
>>> data = 'Watney'         # ok
>>> data = 'Mark Watney'    # ok

3.1.4. Bool

  • Used to inform static type checker that the variable should be bool

Declaration:

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

Example:

>>> data: bool
>>>
>>> data = True     # ok
>>> data = False    # ok
>>> data = None     # error

3.1.5. None

  • Used to inform static type checker that the variable should be None

Declaration:

>>> data: None
>>> data: None = None

Example:

>>> data: None
>>>
>>> data = True     # error
>>> data = False    # error
>>> data = None     # ok

3.1.6. Union

  • Used to inform static type checker that the variable should either X or Y

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

  • int | str == str | int

Declaration:

>>> data: int | float
>>> data: int | float = 1337
>>> data: int | float = 1.337

Example:

>>> data: int | float
>>>
>>> data = 1337     # ok
>>> data = 1.337    # ok
>>> data = 'hello'  # error

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

>>> isinstance(1337, int|float)
True

3.1.7. Optional

  • Used to inform static type checker that the variable should be X or None

  • int | None == None | int

Declaration:

>>> data: int | None
>>> data: int | None = 1337
>>> data: int | None = None

Example:

>>> number: int | None
>>>
>>> number = 1337    # ok
>>> number = None    # ok
>>> number = 1.0     # error

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

>>> isinstance(1337, int|None)
True

3.1.8. Alias

  • Used to make types more readable

Declaration:

>>> data = int | float

Example:

>>> number = int | float
>>>
>>> age: number = 10      # ok
>>> age: number = 10.5    # ok
>>> age: number = None    # error

3.1.9. Final

  • Used to inform static type checker the value should not change

  • Used to define constants

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

In Python there is not such thing as constants. All values can be changed during the runtime. However using Final we can achieve similar effect. Static type checker will ensure that the value should not change during the program.

SetUp:

>>> from typing import Final

Declaration:

>>> data: Final
>>> data: Final[int]
>>> data: Final[float]
>>> data: Final[bool]
>>> data: Final[str]

Definition:

>>> pressure: Final[float] = 1013.25    # ok
>>> pressure = 1024.00                  # error

3.1.10. Literal

SetUp:

>>> from typing import Literal

Declaration:

>>> data: Literal['one', 'two', 'three']

Problem:

>>> agency: str
>>>
>>> agency = 'NASA'         # ok
>>> agency = 'ESA'          # ok
>>> agency = 'Not existing' # ok

Solution:

>>> agency: Literal['NASA', 'ESA', 'POLSA']
>>>
>>> agency = 'NASA'          # ok
>>> agency = 'ESA'           # ok
>>> agency = 'Not existing'  # error

3.1.11. Errors

  • Types are not Enforced

  • This code will run without any problems

  • Types are not required, and never will be

  • Although mypy, pyre-check or pytypes will throw error

>>> name: int = 'Mark Watney'

3.1.12. Use Case - 0x01

>>> firstname: str = 'Mark'
>>> lastname: str = 'Watney'
>>> age: int = 40
>>> adult: bool = True
>>> agency: Literal['NASA', 'ESA', 'POLSA'] = 'NASA'
>>> height: int | float = 185
>>> weight: int | float = 75.5
>>> job: str | None = None

3.1.13. Use Case - 0x02

>>> SECOND: Final[int] = 1
>>> MINUTE: Final[int] = 60 * SECOND
>>> HOUR: Final[int] = 60 * MINUTE
>>> DAY: Final[int] = 24 * HOUR

3.1.14. Further Reading

3.1.15. References

1

Briggs, J. Type Annotations in Python. Year: 2021. Retrieved: 2022-04-08. URL: https://towardsdatascience.com/type-annotations-in-python-d90990b172dc