Skip to Content
Course content

315: Runtime Type Checking vs Static Checking

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Python is a dynamically typed language, which is a fancy way of saying it doesn't care what you put in a variable until the exact moment it tries to do something with it. In small scripts, that's a superpower. In a production codebase with ten other engineers, it's a recipe for a 3:00 AM wake-up call because someone passed a string into a math function.

To wrap our heads around the difference between static and runtime checking, let's build a simple PaymentProcessor. We want a function that takes a payment amount and a currency code and returns a formatted string.

Starting with a fragile payment function

If I just write this the "classic" Python way, it looks like this:

def process_payment(amount, currency):
    return f"Processing {amount} {currency}..."

# This works
print(process_payment(100.0, "USD"))

# This also "works" but is logically broken
print(process_payment("one hundred", "USD")) 

The problem here is that Python doesn't blink. It just concatenates the string "one hundred" into the result. If this were actually hitting a banking API, the API would probably throw a 400 error, or worse, the system would crash deep inside a library where the stack trace is useless.

Adding hints for the editor

To fix this, I'll add type hints. This is where static checking comes in. I'm telling Python—and more importantly, telling my IDE and tools like Mypy—what I expect the types to be.

def process_payment(amount: float, currency: str) -> str:
    return f"Processing {amount} {currency}..."

Now, if I try to pass a string into amount in VS Code or PyCharm, I'll see a yellow squiggle. This is great because it catches the bug while I'm typing, before I even hit "Run".

Realizing hints aren't guards

Here is where I often trip up when I'm moving too fast. I just added those type hints, so I assume the function is now "safe." I'll write a quick test case passing in a string, thinking the type hint will stop it:

# I'm thinking: "The type hint says float, so this will fail early!"
print(process_payment("100", "USD")) 

I run the code... and it works perfectly. Wait, what? That's the crucial realization: Python type hints are ignored at runtime. They are purely documentation for the developer and for static analysis tools. If you don't run a tool like mypy over your code, those hints are essentially just comments.

Enforcing types at the gate

If I'm writing a library that other people will use, I can't trust them to run mypy. I need runtime checking. This means I have to explicitly check the types while the program is actually executing.

I'll modify the function to guard the input using isinstance(). This is a bit more verbose, but it's the only way to guarantee the type is correct at the moment of execution:

def process_payment(amount: float, currency: str) -> str:
    # Runtime check: This actually stops the program if the type is wrong
    if not isinstance(amount, (int, float)):
        raise TypeError(f"Expected amount to be a number, got {type(amount).__name__}")
    
    if not isinstance(currency, str):
        raise TypeError(f"Expected currency to be a string, got {type(currency).__name__}")

    return f"Processing {amount} {currency}..."

# Now this will actually raise a TypeError and stop the program
print(process_payment("100", "USD")) 

Now we have the best of both worlds. The static hints help me write the code faster and catch errors in my IDE, and the runtime checks ensure that if some weird data sneaks in from an external API or a user input, the program crashes immediately with a clear error message rather than corrupting data downstream.




📋 Practical Task

Build a Runtime-Validated User Profile Updater

You are building a function called update_user_profile that takes three arguments: user_id (int), username (str), and age (int).

Your task is to implement both layers of checking:

  1. Add static type hints to the function signature for all three parameters and the return type (which should be bool).
  2. Implement runtime checks using isinstance() for all three parameters. If any parameter is the wrong type, the function should raise a TypeError with a descriptive message.
  3. If all types are correct, return True.

Test your function by passing a string into the age parameter and ensuring it raises the TypeError instead of returning True.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.