# Variable annotations
str = "Alice"
name: int = 30
age: float = 5.9
height: bool = False
is_student:
# 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 + y
8 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
int = 42
x: float = 3.14
y: str = "hello"
z: bool = True
flag: bytes = b"binary data"
data:
# None type
None = None
result: def print_message(msg: str) -> None:
"""Print a message."""
print(msg)
8.4 Collection Types
from typing import List, Dict, Tuple, Set, FrozenSet
# Lists
list[int] = [1, 2, 3] # Python 3.9+
num: int] = [1, 2, 3] # Python 3.5+
num: List[
# Dictionaries
dict[str, int] = {"Alice": 95, "Bob": 87} # Python 3.9+
scores: str, int] = {"Alice": 95, "Bob": 87} # Python 3.5+
scores: Dict[
# Tuples (fixed size)
tuple[float, float] = (3.0, 4.0) # Python 3.9+
point: float, float] = (3.0, 4.0) # Python 3.5+
point: Tuple[
# Tuples (variable size)
tuple[int, ...] = (1, 2, 3, 4, 5) # Python 3.9+
numbers: int, ...] = (1, 2, 3, 4, 5) # Python 3.5+
numbers: Tuple[
# Sets
set[int] = {1, 2, 3} # Python 3.9+
unique_ids: int] = {1, 2, 3} # Python 3.5+
unique_ids: Set[
# Frozen sets
frozenset[str] = frozenset(["a", "b", "c"]) # Python 3.9+
frozen: str] = frozenset(["a", "b", "c"]) # Python 3.5+ frozen: FrozenSet[
8.5 Union Types
from typing import Union
from typing import Optional
# Python 3.10+ pipe syntax (Preferred)
int | str = 42
id_number: int | str = "ABC123"
id_number:
# Union (either type)
int, str] = 42
id_number: Union[int, str] = "ABC123"
id_number: Union[
# All of these are the same:
str | None = "Alice" # Python 3.10+
name: str, None] = "Alice"
name: Union[str] = "Alice" name: Optional[
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
int, int], int] = lambda x, y: x + y operation: Callable[[
def g(x: int) -> str:
return str(x)
5) apply_func(g,
'5'
8.7 Type variables
from typing import TypeVar
= TypeVar('T')
T def identity(x: T) -> T:
"""Return the same value."""
return x
print(type(identity(9)))
9) identity(
<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._value
int] = Box(42)
box_int: Box[ box_int.value
42
str] = Box("hello")
box_str: Box[ 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
# Works! render(Circle())
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."""
pass
="x", mode="b")
open_file(filename# ^^^^^^ Squzzy line will appear
8.11 Type Aliases
from typing import TypeAlias # Python 3.10+
# Simple alias
= list[float]
Vector = list[list[float]]
Matrix
# Python 3.10+ syntax
= int
UserId: TypeAlias = dict[UserId, str]
UserDict: TypeAlias
# Complex alias
= dict[str, Union[str, int, float, bool, None, list['JSON'], dict[str, 'JSON']]]
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):
str
name: int
age: str
email:
# Optional fields
class Employee(TypedDict):
str
name: int
age: str] # Optional field
email: NotRequired[
# 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):
bool
debug: int
timeout: str host:
8.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
int] = 100
MAX_SIZE: Final[= "https://api.example.com" # Type inferred
API_URL: Final
@final
class Constants:
"""Cannot be subclassed."""
pass
class Base:
@final
def method(self) -> None:
"""Cannot be overridden."""
pass