Type Annotations and Type Hints in Python
Description
Type Annotations are a feature introduced in Python 3.5, allowing developers to add type information to variables, function parameters, return values, and more. Type Hints are the practice of static type checking based on annotations, using tools (such as mypy) to detect type errors before code execution, thereby enhancing code readability and robustness.
1. Basic Syntax and Usage
-
Variable Annotations: Directly annotate types for variables.
name: str = "Alice" age: int = 30Annotations do not affect runtime behavior, but IDEs and type-checking tools utilize this information.
-
Function Annotations: Define types for parameters and return values.
def greet(name: str) -> str: return f"Hello, {name}"The type after the arrow
->indicates the return type; the function body itself requires no modification.
2. Complex Types and Container Annotations
For containers like lists and dictionaries, the typing module is required (Python 3.9+ can use built-in types directly):
from typing import List, Dict, Optional
# Annotating lists and dictionaries
def process_data(items: List[int], mapping: Dict[str, int]) -> None:
pass
# Optional type (may be None)
def find_user(id: int) -> Optional[str]:
...
Simplified syntax in Python 3.9+:
def process_data(items: list[int], mapping: dict[str, int]) -> None:
pass
3. Type Aliases and Custom Types
-
Type Aliases: Simplify complex annotations.
from typing import Dict, Tuple # Alias examples Coordinate = Tuple[float, float] UserMap = Dict[int, str] def locate(point: Coordinate) -> UserMap: ... -
Custom Types: Use
NewTypeorTypeAlias(Python 3.10+).from typing import NewType UserId = NewType('UserId', int) id = UserId(1001) # Still int at runtime, but distinguished during type checking
4. Union Types and Literal Types
-
Union Types: Allow multiple types.
from typing import Union def display(value: Union[int, str]) -> None: print(value) # Python 3.10+ supports the | operator def display_v2(value: int | str) -> None: ... -
Literal Types: Restrict to specific values.
from typing import Literal def set_direction(direction: Literal["left", "right"]) -> None: ...
5. Using Type Checking Tools
Install mypy and check your code:
pip install mypy
mypy your_script.py
Example:
# Example code (save as test.py)
def add(a: int, b: int) -> int:
return a + b
result = add(1, "2") # Type error!
Running mypy test.py will report an error:
test.py:4: error: Argument 2 to "add" has incompatible type "str"; expected "int"
6. Advanced Features: Generics and Protocols
-
Generics: Enable functions or classes to support multiple types.
from typing import TypeVar, List T = TypeVar('T') def first_item(items: List[T]) -> T: return items[0] -
Protocols: Structural typing (static checking for duck typing).
from typing import Protocol class Renderable(Protocol): def render(self) -> str: ... def render_item(item: Renderable) -> None: print(item.render())
Summary
Type Annotations, by providing explicit type constraints combined with tools (like mypy), help detect errors early, which is especially beneficial for large projects. However, note that:
- Annotations are only hints and do not affect runtime;
- They can be adopted incrementally, allowing gradual addition of annotations;
- The
Anytype can be used to bypass checks flexibly (but use it cautiously).