x ai python type hint 2
ai generated
Python Type Hints: A Comprehensive Tutorial
Type hints (introduced in Python 3.5 via PEP 484) are a powerful feature that allow you to annotate your code with expected types. They are not enforced at runtime by Python itself, but they enable static type checkers (like mypy), better IDE support (autocompletion, error detection), and improved code readability and maintainability.
1. Getting Started
Basic Syntax
def greet(name: str) -> str: """Return a greeting message.""" return f"Hello, {name}!" # Variable annotations (Python 3.6+) age: int = 25 scores: list[float] = [95.5, 87.0, 92.3]
: typeafter a parameter name.-> return_typeafter the parameter list for the return value.
Running Type Checkers
Install mypy (the most popular static type checker):
pip install mypy mypy my_script.py
2. Built-in Types
| Python Type | Type Hint Example | Notes |
|---|---|---|
int |
x: int = 42 |
Integers |
float |
pi: float = 3.14 |
Floating point |
str |
name: str = "Alice" |
Strings |
bool |
is_active: bool = True |
Booleans |
bytes |
data: bytes = b"hello" |
Byte sequences |
list |
numbers: list[int] |
Python 3.9+ |
dict |
mapping: dict[str, int] |
Python 3.9+ |
tuple |
coords: tuple[float, float] |
Fixed length |
set |
unique: set[int] |
Python 3.9+ |
For older Python versions (before 3.9) use typing module:
from typing import List, Dict, Tuple, Set numbers: List[int] = [1, 2, 3] mapping: Dict[str, int] = {"age": 30}
3. Common typing Constructs
Optional, Union, Any
from typing import Optional, Union, Any # Optional = Union[T, None] def find_user(user_id: int) -> Optional[str]: # Returns str or None ... # Union (now | syntax in 3.10+) def process(data: Union[int, str, None]) -> None: ... # Modern syntax (Python 3.10+) def process(data: int | str | None) -> None: ... # Any = disable type checking def risky_function(x: Any) -> Any: return x.something() # No warning
Generics with Type Variables
from typing import TypeVar, Generic T = TypeVar("T") # Can be any type def first_element(lst: list[T]) -> T | None: return lst[0] if lst else None # Generic class class Stack(Generic[T]): def __init__(self) -> None: self.items: list[T] = [] def push(self, item: T) -> None: self.items.append(item) def pop(self) -> T | None: return self.items.pop() if self.items else None
4. Collections and More
from collections.abc import Sequence, Mapping, Iterable from typing import Callable def process_sequence(items: Sequence[int]) -> None: """Accepts list, tuple, etc.""" ... def callback_handler(func: Callable[[int, str], bool]) -> None: """Function that takes (int, str) and returns bool.""" ...
5. Custom Types and Classes
from dataclasses import dataclass from typing import TypedDict class User: def __init__(self, name: str, age: int) -> None: self.name = name self.age = age # Dataclass (Python 3.7+) @dataclass class Point: x: float y: float # TypedDict (structured dictionaries) class UserDict(TypedDict): name: str age: int active: bool
6. Type Aliases and NewType
from typing import TypeAlias, NewType # Simple alias UserId: TypeAlias = int # NewType - creates distinct type for type checkers UserIdStrict = NewType("UserIdStrict", int) def get_user(user_id: UserIdStrict) -> str: ...
7. Advanced Features
Protocols (Structural Subtyping)
from typing import Protocol class SupportsClose(Protocol): def close(self) -> None: ... def close_resource(resource: SupportsClose) -> None: resource.close()
Self (Python 3.11+)
from typing import Self class Shape: def scale(self, factor: float) -> Self: # Returns instance of the same class ... return self
Literal and Final
from typing import Literal, Final status: Literal["success", "error", "pending"] = "success" MAX_RETRIES: Final[int] = 5 # Cannot be reassigned
8. Practical Examples
Example 1: A Simple CLI Tool
from typing import List, Optional def parse_args(argv: List[str]) -> Optional[int]: if len(argv) < 2: return None try: return int(argv[1]) except ValueError: return None
Example 2: Generic Data Processor
from typing import TypeVar, Callable T = TypeVar("T") U = TypeVar("U") def map_list(lst: list[T], func: Callable[[T], U]) -> list[U]: return [func(item) for item in lst]
9. Best Practices
- Start simple — Add hints gradually.
- Use
Anysparingly — Only when truly dynamic. - Be precise — Prefer
Sequenceoverlistwhen order matters but mutability doesn't. - Document with types — Type hints often replace some docstring descriptions.
- Ignore when necessary:
def legacy_code() -> None: ... # type: ignore
- Configure mypy with
pyproject.toml:
[tool.mypy] python_version = "3.11" warn_return_any = true strict = true
10. Common Pitfalls
- Type hints are not runtime validation (use
pydanticfor that). - Forward references: Use strings or
from __future__ import annotations(Python 3.7+ recommended). - Mutable defaults are still dangerous even with types.
# Bad def append(item: int, lst: list[int] = []) -> list[int]: # Shared default! # Good def append(item: int, lst: list[int] | None = None) -> list[int]: if lst is None: lst = [] lst.append(item) return lst
11. Further Reading
- Official PEP 484: https://peps.python.org/pep-0484/
- mypy documentation: https://mypy.readthedocs.io/
- Python Typing Documentation: https://docs.python.org/3/library/typing.html
- Real Python Tutorial on Type Hints
typingmodule evolution (Python 3.9–3.12 brought huge improvements)
Happy typing! 🎯
Type hints make large codebases significantly more maintainable. Start using them today — your future self (and your teammates) will thank you.
This tutorial is self-contained and covers everything from basics to advanced topics. You can copy-paste the code examples directly into your editor.