Skip to main content

How to enforce type hinting in Python: Static vs Runtime Strategies

· 5 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

Python is famous for being a "consenting adults" language. By default, type hints (like name: str) are just polite suggestions. If you pass an integer into a function expecting a string, Python will happily execute it-and probably crash three lines later.

In 2026, relying on "polite suggestions" isn't enough for production-grade code. To actually enforce type hinting, you have to move beyond the built-in typing module and use external guardians.

🏗️ Method 1: Static Enforcement (The "Gatekeeper")

The most common way to enforce types is Static Analysis. This happens before your code even runs, usually in your IDE or as part of your CI/CD pipeline.

The Tool: MyPy

MyPy scans your source code, follows the logic, and flags every place where a variable's type doesn't match its hint.

How to use it:

  1. Install: pip install mypy
  2. Run: mypy your_script.py

The Code Example:

# calculator.py
def add_numbers(a: int, b: int) -> int:
return a + b

# This will run fine in standard Python, but MyPy will scream.
add_numbers(10, "20")

MyPy Output: error: Argument 2 to "add_numbers" has incompatible type "str"; expected "int"


🛡️ Method 2: Runtime Enforcement (The "Bouncer")

Sometimes you need the code to physically stop and throw an error if a bad type is passed in at runtime (e.g., data coming from an API).

The Tool: Pydantic (For Data Models)

Pydantic is the industry standard for enforcing types in classes and data structures. It doesn't just "hint"; it validates and even coerces data.

from pydantic import BaseModel, ValidationError

class User(BaseModel):
id: int
username: str

try:
# This will fail because 'id' is a string that can't be an int
user = User(id="not_an_int", username="gemini_user")
except ValidationError as e:
print(f"🛑 Stop right there: {e}")

The Tool: Beartype (For Functions)

If you want your functions to throw a TypeError the second a bad argument hits them, Beartype is the fastest, "O(1)" runtime type checker available.

from beartype import beartype

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

greet(12345) # ❌ This raises a BeartypeCallHintViolation immediately!

🚀 The "2026 Pro Workflow": Pre-commit Hooks

The ultimate way to enforce type hinting is to make it impossible to even push code that has type errors. You do this by combining MyPy with Pre-commit.

Your .pre-commit-config.yaml might look like this:

repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
args: [--strict] # Forces you to hint EVERY variable

📊 Which Enforcement Strategy Should You Choose?

StrategyToolsProsCons
StaticMyPy, PyrightZero performance hit; catches bugs early.Doesn't catch bad data from APIs/Files.
RuntimePydantic, BeartypeGuarantees data integrity at execution.Small performance overhead.
Strict Modepyright --strictHighest possible code quality.Can be frustratingly pedantic.

📚 Sources & Technical Refs

More on python