# Variable annotations
name: str = "Alice"
age: int = 30
height: float = 5.9
is_student: bool = False
# Function annotations
def greet(name: str) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
# Function with multiple parameters
def add(x: int, y: int) -> int:
"""Add two numbers."""
return x + y8 Type hints cheat sheet
See also: https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html
8.1 Summary Comparison Table
| Feature | Python 3.5-3.8 | Python 3.9+ | Python 3.10+ | Python 3.11+ |
|---|---|---|---|---|
| Basic types | List[int] |
list[int] |
list[int] |
list[int] |
| Union types | Union[int, str] |
Union[int, str] |
int \| str |
int \| str |
| Optional | Optional[str] |
Optional[str] |
str \| None |
str \| None |
| Type alias | Vector = List[float] |
Vector = list[float] |
Vector: TypeAlias = list[float] |
Same as 3.10 |
| Self type | Use TypeVar | Use TypeVar | Use TypeVar | Self |
| NotRequired | Not available | Not available | Not available | NotRequired[T] |
| TypeGuard | Not available | Not available | TypeGuard |
TypeGuard |
8.2 Basic Syntax
8.3 Built-in types
# Primitive types
x: int = 42
y: float = 3.14
z: str = "hello"
flag: bool = True
data: bytes = b"binary data"
# None type
result: None = None
def print_message(msg: str) -> None:
"""Print a message."""
print(msg)8.4 Collection Types
from typing import List, Dict, Tuple, Set, FrozenSet
# Lists
num: list[int] = [1, 2, 3] # Python 3.9+
num: List[int] = [1, 2, 3] # Python 3.5+
# Dictionaries
scores: dict[str, int] = {"Alice": 95, "Bob": 87} # Python 3.9+
scores: Dict[str, int] = {"Alice": 95, "Bob": 87} # Python 3.5+
# Tuples (fixed size)
point: tuple[float, float] = (3.0, 4.0) # Python 3.9+
point: Tuple[float, float] = (3.0, 4.0) # Python 3.5+
# Tuples (variable size)
numbers: tuple[int, ...] = (1, 2, 3, 4, 5) # Python 3.9+
numbers: Tuple[int, ...] = (1, 2, 3, 4, 5) # Python 3.5+
# Sets
unique_ids: set[int] = {1, 2, 3} # Python 3.9+
unique_ids: Set[int] = {1, 2, 3} # Python 3.5+
# Frozen sets
frozen: frozenset[str] = frozenset(["a", "b", "c"]) # Python 3.9+
frozen: FrozenSet[str] = frozenset(["a", "b", "c"]) # Python 3.5+8.5 Union Types
from typing import Union
from typing import Optional
# Python 3.10+ pipe syntax (Preferred)
id_number: int | str = 42
id_number: int | str = "ABC123"
# Union (either type)
id_number: Union[int, str] = 42
id_number: Union[int, str] = "ABC123"
# All of these are the same:
name: str | None = "Alice" # Python 3.10+
name: Union[str, None] = "Alice"
name: Optional[str] = "Alice" 8.6 Callable types
from typing import Callable
# Callable types
def apply_func(f: Callable[[int], str], x: int) -> str:
"""Apply function f to x."""
return f(x)
# More specific callable
operation: Callable[[int, int], int] = lambda x, y: x + ydef g(x: int) -> str:
return str(x)apply_func(g, 5)'5'
8.7 Type variables
from typing import TypeVar
T = TypeVar('T')
def identity(x: T) -> T:
"""Return the same value."""
return xprint(type(identity(9)))
identity(9)<class 'int'>
9
8.8 Generic Classes
# Generic classes
from typing import Generic
class Box(Generic[T]):
def __init__(self, value: T) -> None:
"""Initialize box with value."""
self._value = value
@property
def value(self) -> T:
"""Get the value."""
return self._valuebox_int: Box[int] = Box(42)
box_int.value42
box_str: Box[str] = Box("hello")
box_str.value'hello'
8.9 Protocol (similar to interface)
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None:
"""Draw the object."""
...
class Circle:
def draw(self) -> None:
"""Draw a circle."""
print("Drawing circle")
def render(obj: Drawable) -> None:
"""Render any drawable object."""
obj.draw()
# Circle implements Drawable protocol
render(Circle()) # Works!Drawing circle
8.10 Literal Types
from typing import Literal
def open_file(filename: str, mode: Literal["r", "w", "a"]) -> None:
# ^^^^^^^^^^^^ IDE autocheck args
"""Open a file in specified mode."""
passopen_file(filename="x", mode="b")
# ^^^^^^ Squzzy line will appear8.11 Type Aliases
from typing import TypeAlias # Python 3.10+
# Simple alias
Vector = list[float]
Matrix = list[list[float]]
# Python 3.10+ syntax
UserId: TypeAlias = int
UserDict: TypeAlias = dict[UserId, str]
# Complex alias
JSON = dict[str, Union[str, int, float, bool, None, list['JSON'], dict[str, 'JSON']]]
# Using aliases
def process_vector(v: Vector) -> float:
"""Process a vector."""
return sum(v)8.12 TypedDict
from typing import TypedDict
from typing import NotRequired # Python 3.11+
# Define structured dictionary
class Person(TypedDict):
name: str
age: int
email: str
# Optional fields
class Employee(TypedDict):
name: str
age: int
email: NotRequired[str] # Optional field
# Using TypedDict
person: Person = {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
# Python 3.8+ total=False for all optional
class Config(TypedDict, total=False):
debug: bool
timeout: int
host: str8.13 Overloading
from typing import overload
@overload
def process(x: int) -> str:
...
@overload
def process(x: str) -> int:
...
def process(x: Union[int, str]) -> Union[str, int]:
"""Process input based on type."""
if isinstance(x, int):
return str(x)
else:
return len(x)8.14 Final and Constants
from typing import Final
from typing import final # Final methods and classes
# Constants
MAX_SIZE: Final[int] = 100
API_URL: Final = "https://api.example.com" # Type inferred
@final
class Constants:
"""Cannot be subclassed."""
pass
class Base:
@final
def method(self) -> None:
"""Cannot be overridden."""
pass