x ai python type hint

By Xah Lee. Date: .

x ai python type hint

ai generated

Python Type Hints Tutorial

Type hints (also called type annotations) were introduced in Python 3.5 via PEP 484. They allow you to declare the expected types of variables, function parameters, and return values.

Important points:

1. Basic Syntax

# Variable annotations (Python 3.6+)
age: int = 25
name: str = "Alice"
is_active: bool = True
score: float = 95.5
data: list[int] = [1, 2, 3]          # Python 3.9+ built-in generics
coords: tuple[float, float] = (10.5, 20.3)

For older Python versions (before 3.9), use typing module:

from typing import List, Tuple

data: List[int] = [1, 2, 3]
coords: Tuple[float, float] = (10.5, 20.3)

2. Function Annotations

def greet(name: str) -> str:
    return f"Hello, {name}!"

def add(a: int, b: int) -> int:
    return a + b

# Optional parameters
from typing import Optional

def find_user(user_id: int) -> Optional[str]:
    # returns str or None
    ...

None as return type:

def log(message: str) -> None:
    print(message)   # no return value

3. Common Types from typing Module

Type Description Example
List[T] List of type T List[int]
Dict[K, V] Dictionary with key K, value V Dict[str, int]
Set[T] Set of type T Set[str]
Tuple[T, ...] Tuple (fixed or variable length) Tuple[int, str]
Optional[T] T or None (equivalent to `T None`)
Union[T1, T2] T1 or T2 (new syntax: T1 | T2) int | str
Any Any type (disables checking) Any
NoReturn Function never returns (e.g. sys.exit) NoReturn

Modern union syntax (Python 3.10+):

def process(value: int | str) -> None:
    ...

4. Collections with Generics (Python 3.9+)

def process_items(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

5. Classes and Self

from typing import Self   # Python 3.11+

class User:
    name: str
    age: int

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

    def copy(self) -> Self:          # returns instance of same class
        return User(self.name, self.age)

6. Advanced Features

TypedDict (structured dictionaries)

from typing import TypedDict

class UserDict(TypedDict):
    name: str
    age: int
    active: bool

def create_user(data: UserDict) -> None:
    ...

Literal types (exact values)

from typing import Literal

def set_status(status: Literal["active", "inactive", "banned"]) -> None:
    ...

Protocols (structural subtyping - "duck typing" for types)

from typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None: ...

def close_resource(res: SupportsClose) -> None:
    res.close()

Generics (custom generic classes/functions)

from typing import TypeVar, Generic

T = TypeVar("T")

class Box(Generic[T]):
    def __init__(self, value: T):
        self.value = value

    def get(self) -> T:
        return self.value

string_box: Box[str] = Box("hello")

Callable (functions as types)

from collections.abc import Callable

def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
    return func(a, b)

7. Type Aliases and NewType

from typing import TypeAlias, NewType

# Simple alias
UserId: TypeAlias = int

# Distinct type for type checkers (runtime same as int)
UserIdStrict = NewType("UserIdStrict", int)

def get_user(uid: UserIdStrict) -> str:
    ...

8. Type Checking in Practice

Install a type checker:

pip install mypy
mypy my_script.py          # or mypy .

Configuration (pyproject.toml or mypy.ini):

[tool.mypy]
python_version = "3.12"
strict = true
disallow_untyped_defs = true

Popular IDE support:

9. Common Patterns & Tips

# 1. Forward references (when class not yet defined)
class Node:
    children: list["Node"]     # string quotes in older Python

# 2. Ignoring type errors (when necessary)
x: int = 5
y = x + "hello"   # type: ignore

# 3. Revealing type during development
from typing import reveal_type

reveal_type(some_variable)   # mypy will print inferred type

10. Complete Example

from typing import TypedDict, Literal
from collections.abc import Sequence

class Point(TypedDict):
    x: float
    y: float

def move(point: Point, direction: Literal["up", "down", "left", "right"]) -> Point:
    if direction == "up":
        point["y"] += 1
    # ... other directions
    return point

def process_points(points: Sequence[Point]) -> list[Point]:
    return [move(p.copy(), "up") for p in points]   # .copy() for TypedDict in 3.11+

Resources

Best Practice Recommendation: Start adding type hints gradually. Use strict = true in mypy once your codebase is mostly annotated. Tools like pyright or VS Code can help you incrementally improve type coverage.

Type hints make large Python codebases significantly more maintainable. Happy typing!