3 Python Type Annotations

Many languages require that a variable must declare a its type which permanently set what can be assigned to it. In python only the objects have a type.

Common Primitive Types

Type name Sample Values
int 0, 148, -3
float 4.5, -3.58
str 'hello world'
bool True
None None

Compound Types

Type Description Example
list[T] a list whose elements are all of type T [1, 2, 3] has type list[int]. The nested list [[1, 2, 3], [-2]] has type list[list[int]]
dict[T1, T2] a dictionary whose keys are of type T1 and whose values are of type T2 {'a': 1, 'b': 2, 'c': 3} has type dict[str, int]
tuple[T1, T2, ...] a tuple whose first element has type T1, second element has type T2, etc. ('hello', True, 3.4) has type tuple[str, bool, float]

Annotating Functions

def split_numbers(numbers: List[int]) -> Tuple[List[int], List[int]]:
    """
    Return a tuple of lists, where the first list contains the numbers
    that are >= 0, and the second list contains the numbers that are < 0.
    """
    pos = []
    neg = []
    for n in numbers:
        if n >= 0:
            pos.append(n)
        else:
            neg.append(n)
    return pos, neg

Annotating Instance Attributes

class Inventory:
    """
    The inventory of a store.

    Keeps track of all of the items available for sale in 
    the store.

    Attributes:
        size: the total number of items available for sale.
        items: a dictionary mapping an id number to a 
        tuple with the 
               item's description and number in stock.
    """
    size: int
    items: Dict[int, Tuple[str, int]]

Annotating Methods of a Class

Here we might need to a special import for class type annotations:


from __future__ import annotations

class Inventory:
    """
    The inventory of a store.
    """

    # The type of self is omitted.
    def __init__(self) -> None:
        ...
    
    def add_item(self, item: str, quantity: int) -> None:
        ...
    
    def get_stock(self, item: str) -> int:
        ...
    
    def compare(self, other: Inventory) -> bool:
        ...
    
    def copy(self) -> Inventory:
        ...
    
    def merge(self, others: list[Inventory]) -> None:
        ...

More Advanced Types

From the typing module we have:
from typing import

  1. Any which can be anything
  2. Union if we want it to be one of two different types for example: Union[int,float]
  3. Optional for example Optional[int] which is equivalent to Union[int, None]
  4. Callable when the type is itself a function. It takes two expressions in square brackets: the first is a list of types, representing the types of the function’s arguments; the second is its return type. For example Callable[[int, str], bool].