Mathew K Analytics

Lesson 19 · Python standard library deep dive

Python typing & enum Explained: Type Hints Done Right | Standard Library #19

Video nineteen of the twenty-five-part series: typing, for type hints and static analysis, and enum, for real enumerations. Optional, Union, generics,…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Python Standard Library Deep-Dive, Video 19: typing and enum#

  • Video nineteen of the twenty-five-part series: typing, for type hints and static analysis, and enum, for real enumerations.
  • Optional, Union, generics, Protocol, TypedDict, plus Enum, IntEnum, auto, and Flag.
  • Let's get into it.

Part 1: Why Type Hints#

def add(a: int, b: int) -> int:
    return a + b
print(add(2, 3))
print(add('a', 'b'))
print(add.__annotations__)
5
ab
{'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}

Part 2: Basic Type Hints - Variables, Parameters, Returns#

name: str = 'Ana'
age: int = 30
scores: list
scores = [85, 90, 78]
def greet(person: str, times: int = 1) -> str:
    return (f'Hello, {person}! ' * times).strip()
print(greet('Sam', times=2))
Hello, Sam! Hello, Sam!

Part 3: Optional and Union#

from typing import Optional, Union
def find_user(user_id: int) -> Optional[str]:
    users = {1: 'Ana', 2: 'Sam'}
    return users.get(user_id)
print(find_user(1))
print(find_user(99))
def parse_value(raw: str) -> Union[int, float, str]:
    if raw.isdigit():
        return int(raw)
    try:
        return float(raw)
    except ValueError:
        return raw
print(parse_value('42'), parse_value('3.14'), parse_value('hello'))
Ana
None
42 3.14 hello
def modern_optional(value: int | None = None) -> str:
    return 'none' if value is None else str(value)
print(modern_optional())
print(modern_optional(7))
none
7

Part 4: Generic Containers - list[int], dict[str, int], tuple#

def average(values: list[int]) -> float:
    return sum(values) / len(values)
print(average([10, 20, 30]))
def word_lengths(words: list[str]) -> dict[str, int]:
    return {w: len(w) for w in words}
print(word_lengths(['hi', 'there', 'friend']))
def coordinates() -> tuple[int, int]:
    return (3, 4)
print(coordinates())
20.0
{'hi': 2, 'there': 5, 'friend': 6}
(3, 4)

Part 5: Callable and Any#

from typing import Callable, Any
def apply_twice(func: Callable[[int], int], value: int) -> int:
    return func(func(value))
print(apply_twice(lambda x: x * 2, 3))
def log_anything(value: Any) -> None:
    print(f'logged: {value!r}')
log_anything(42)
log_anything('text')
log_anything([1, 2, 3])
12
logged: 42
logged: 'text'
logged: [1, 2, 3]

Part 6: TypedDict#

from typing import TypedDict
class Movie(TypedDict):
    title: str
    year: int
    rating: float
def describe(movie: Movie) -> str:
    return f"{movie['title']} ({movie['year']}): {movie['rating']}/10"
m: Movie = {'title': 'Arrival', 'year': 2016, 'rating': 8.0}
print(describe(m))
print(type(m))
Arrival (2016): 8.0/10
<class 'dict'>

Part 7: Protocol - Structural Typing#

from typing import Protocol
class SupportsArea(Protocol):
    def area(self) -> float: ...
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14159 * self.radius ** 2
class Square:
    def __init__(self, side):
        self.side = side
    def area(self):
        return self.side ** 2
def total_area(shapes: list[SupportsArea]) -> float:
    return sum(shape.area() for shape in shapes)
print(total_area([Circle(2), Square(3)]))
21.56636

Part 8: enum.Enum Basics#

from enum import Enum
class Status(Enum):
    PENDING = 1
    ACTIVE = 2
    COMPLETED = 3
s = Status.ACTIVE
print(s)
print(s.name)
print(s.value)
print(s == Status.ACTIVE)
print(s == 2)
print(list(Status))
Status.ACTIVE
ACTIVE
2
True
False
[<Status.PENDING: 1>, <Status.ACTIVE: 2>, <Status.COMPLETED: 3>]

Part 9: IntEnum, auto(), and Flag#

from enum import IntEnum, auto, Flag
class Priority(IntEnum):
    LOW = auto()
    MEDIUM = auto()
    HIGH = auto()
print(Priority.HIGH == 3)
print(Priority.HIGH > Priority.LOW)
class Permission(Flag):
    READ = auto()
    WRITE = auto()
    EXECUTE = auto()
combined = Permission.READ | Permission.WRITE
print(combined)
print(Permission.READ in combined)
print(Permission.EXECUTE in combined)
True
True
Permission.READ|WRITE
True
False

Part 10: A Real Pattern - Enum-Driven State Machine#

class OrderState(Enum):
    CREATED = 'created'
    PAID = 'paid'
    SHIPPED = 'shipped'
    DELIVERED = 'delivered'
VALID_TRANSITIONS: dict[OrderState, list[OrderState]] = {
    OrderState.CREATED: [OrderState.PAID],
    OrderState.PAID: [OrderState.SHIPPED],
    OrderState.SHIPPED: [OrderState.DELIVERED],
    OrderState.DELIVERED: [],
}
def transition(current: OrderState, target: OrderState) -> OrderState:
    if target not in VALID_TRANSITIONS[current]:
        raise ValueError(f'cannot go from {current} to {target}')
    return target
order = OrderState.CREATED
order = transition(order, OrderState.PAID)
print(order)
try:
    transition(order, OrderState.DELIVERED)
except ValueError as e:
    print(f'caught: {e}')
OrderState.PAID
caught: cannot go from OrderState.PAID to OrderState.DELIVERED

Wrap-Up: What You Learned#

  • Type hints document expected types for tools and editors; Python itself never enforces them at runtime.
  • Optional[X] and X | None both mean 'X or None'; Union expresses 'one of several types'.
  • Built-in containers can be parameterized directly: list[int], dict[str, int], tuple[int, int].
  • Callable[[Args], Return] hints function-shaped values; Any opts a value out of type checking entirely.
  • TypedDict describes an expected dict shape; at runtime it's still just an ordinary dict.
  • Protocol enables structural typing: any object satisfying the required methods qualifies, no inheritance needed.
  • Enum creates a fixed, named set of distinct constant values, safer than magic strings or numbers.
  • IntEnum members compare equal to plain ints; auto() assigns values automatically; Flag supports bitwise combination.
  • A real pattern: combining Enum and type hints to model valid states and enforce legal transitions.
  • That wraps up typing and enum. Next up: unittest, for writing and running real automated tests.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.