Python Type Hints: Lying to Your Future Self, But Politely

· 2 min read · Syed Omar Faruk Towaha
Python Type Hints: Lying to Your Future Self, But Politely

Here is a fun fact that confuses every new Python developer: this code runs perfectly.

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

print(add("hello ", "world"))  # hello world

Python reads your type hints, nods politely, and ignores them completely. The interpreter does not check types. The hints are, at runtime, just annotations sitting in a dictionary, like sticky notes on a fridge that nobody reads.

So why bother? Because other tools read them, and those tools are much more pedantic than Python.

Who actually reads your hints

mypy catching bugs
Two real bugs found without running a single line of code.

The classic bug hints catch: None

Most production bugs I've seen in Python are some variation of "this was None and nobody expected it."

def find_user(user_id: int) -> User | None:
    ...

user = find_user(42)
send_email(user.email)  # mypy: "User | None" has no attribute "email"

The type checker forces the uncomfortable conversation early:

user = find_user(42)
if user is None:
    raise UserNotFound(42)
send_email(user.email)  # now it's fine

That one if is a 2 AM page you will never receive.

Where the lies creep in

Type hints are only as honest as the person writing them. Some of my favourite polite lies:

from dataclasses import dataclass
from decimal import Decimal

@dataclass(frozen=True)
class Invoice:
    customer_id: int
    total: Decimal
    currency: str = "CAD"

Now the shape of your data is documented, checked, and immutable. Your code reads like a contract instead of a rumour.

Start small

You don't have to annotate a 50,000-line project in a weekend. Add hints to new code and to functions you touch. Run mypy in CI with a lenient config, then tighten it slowly. Type hints are like flossing: annoying to start, impossible to justify skipping once you notice the difference.

And remember: Python will still let you pass a string where an int should go. The hints are a promise, not a cage. Just try to keep your promises.

// related

// prefer the terminal?

Open the terminal blog and type read python-type-hints-polite-lies.