Skip to main content
CodeOath
← All posts

Python105 min total · 18 parts

Python Fundamentals for Interviews: Data Structures, Comprehensions, and Gotchas

Part 16 of 18 · ~1 min

Type Hints

Nothing about writing ip: str on a parameter makes Python check, at any point, that the caller actually passed a string. Call parse_line(404) and it runs exactly as far as it would have without the hint, right up until something inside tries to call .split() on an integer and fails — the annotation never intervened. What the hint does is give a separate tool something to check on your behalf: mypy or pyright can read ip: str and flag parse_line(404) as wrong before the program ever runs, an editor can use it to autocomplete .split( the moment you type raw., and a reader six months from now gets the function's contract without needing a comment that could quietly go stale.

def parse_line(line: str) -> LogEntry:
    ...

from typing import Optional

def lookup_geo(ip: str) -> Optional[dict]:   # returns a dict, or None if the lookup failed
    ...

def lookup_geo(ip: str) -> dict | None:      # 3.10+ shorthand for the same thing
    ...
from dataclasses import dataclass

@dataclass
class LogEntry:
    ip: str
    method: str
    path: str
    status: int
    duration_ms: int

e = LogEntry("203.0.113.42", "GET", "/api/search", 200, 118)

This is the same LogEntry from the very first chapter's namedtuple, wearing modern clothes. namedtuple gives you named fields and stays a tuple underneath — immutable, unpackable, hashable. @dataclass gives you named, typed fields and stays an ordinary mutable object underneath, generating __init__, __repr__, and __eq__ for you automatically — the same three dunders written by hand for Report two chapters ago. Reach for namedtuple when a record should be frozen the moment it's created; reach for @dataclass when fields might legitimately change afterward, or when a type checker should be watching them.