Function Annotations and Type Hints#
Annotations attach metadata to parameters and return values. Type hints (PEP 484+) use annotations to document expected types for static checkers (mypy, pyright) — they do not enforce types at runtime by default.
How to use this page
Basics in Intermediate Syntax. Deep dive: Type Hints and Annotations.
At a glance
| Track | Python Advanced → Advanced Functions |
| Sections | 7 major topics |
| Outline | Use the right-hand TOC to jump |
Topics: Syntax · Modern typing (3.9+ / 3.10+) · Common type forms · TypedDict and dataclass hints · Forward references and quotes · Runtime checking (optional) · Best practices for interviews
- Syntax
- Modern typing (3.9+ / 3.10+)
- Common type forms
TypedDictand dataclass hints- Forward references and quotes
- Runtime checking (optional)
- Best practices for interviews
Syntax#
def greet(name: str, excited: bool = False) -> str:
msg = f"Hello, {name}"
return msg + "!" if excited else msg
greet.__annotations__
# {'name': <class 'str'>, 'excited': <class 'bool'>, 'return': <class 'str'>}
Annotations are stored at function definition time — any expression is valid:
Modern typing (3.9+ / 3.10+)#
# Built-in generics (3.9+)
def merge(a: list[int], b: list[int]) -> list[int]:
return sorted(a + b)
# Union with | (3.10+)
def find(items: list[str], target: str) -> str | None:
...
# Callable
from collections.abc import Callable
def apply(fn: Callable[[int, int], int], a: int, b: int) -> int:
return fn(a, b)
Common type forms#
| Need | Hint |
|---|---|
| Optional value | T \| None or Optional[T] |
| Any type | Any (escape hatch) |
| Dict map | dict[str, int] |
| Fixed tuple | tuple[int, int, str] |
| Variable tuple | tuple[int, ...] |
| Literal values | Literal["r", "w"] |
| Type variable | TypeVar("T") |
| Protocol / structural | Protocol class |
from typing import TypeVar, Literal
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
Mode = Literal["read", "write"]
def open_mode(mode: Mode) -> None: ...
TypedDict and dataclass hints#
from typing import TypedDict
class User(TypedDict):
name: str
age: int
def process(user: User) -> str:
return user["name"]
Runtime: still a plain dict — checker enforces keys statically.
Forward references and quotes#
class Node:
def __init__(self, val: int, next: "Node | None" = None):
self.val = val
self.next = next
# 3.7+ from __future__ import annotations — postpone evaluation
from __future__ import annotations
class Node:
def __init__(self, val: int, next: Node | None = None):
...
Runtime checking (optional)#
Type hints are ignored at runtime unless you use:
mypy,pyright,pytype— static analysistypeguard,beartype— runtime decoratorsisinstancechecks you write manually
def add(a: int, b: int) -> int:
return a + b
add("1", "2") # runs — returns "12" (str concat if overloaded?)
add("1", 2) # TypeError at runtime for str + int
Best practices for interviews#
- Hint public function signatures
- Use
list[int]notList[int]in 3.9+ code - Don't over-annotate every local variable
- Match platform Python version on assessments
Interview traps (quick reference)#
| Trap | What goes wrong | Safe approach |
|---|---|---|
| Hints enforce runtime | False sense of safety | Use checker or validate |
Any everywhere |
Defeats purpose | Specific types |
| Mutable default + hint | Still shared default bug | None sentinel |
list vs List |
Style/version mix | Pick one per codebase |
Mental model checklist#
- Where are annotations stored?
- Do hints slow down Python at runtime?
- What is
X | Noneexpressing? - When use
Callable[[int], str]?
What's next#
| Topic | Page |
|---|---|
| Full typing guide | Type Hints and Annotations |
| Intermediate syntax | Intermediate Syntax and Structures |
| Callable protocol | Callable Objects |