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