The TypeError: 'NoneType' object is not subscriptable error appearing in production is a nightmare for every developer. Python is a dynamically typed language, allowing variables to be assigned freely without type declarations. However, once a project exceeds 10,000 lines of code, this freedom often becomes a maintenance burden.
Mypy is a tool that brings the power of static typing to Python. It preserves the language’s flexibility while ensuring codebase safety. In a project handling 500,000 financial transaction records, I once spent an entire day just to find a None variable incorrectly passed into a nested function. With Mypy, this error would have been detected in just 2 seconds during a check.
Quick start: Install and use Mypy in 2 minutes
First, install the library via pip using the following command:
pip install mypy
Consider the example in the main.py file below:
def tinh_tong(a: int, b: int) -> int:
return a + b
# Call the function with correct types
print(tinh_tong(10, 20))
# Pass incorrect data type (string instead of int)
print(tinh_tong(10, "20"))
If run with Python, the program will crash midway. With Mypy, you check for errors using the command:
mypy main.py
The system will pinpoint the line with the error:
main.py:8: error: Argument 2 to "tinh_tong" has incompatible type "str"; expected "int"
Found 1 error in 1 file (checked 1 source file)
Mypy specifically identifies line 8 as having a type mismatch. Once you fix the code and receive a Success message, you can be fully confident in your data consistency.
Why are large projects required to use Mypy?
Many developers are often hesitant to write type hints for fear of wasting time. However, after many real-world projects, I’ve found that Mypy provides 4 outstanding benefits:
- Reduce Unit Test Load: You don’t need to write tests just to check if the input is a number. Mypy scans the entire codebase and validates that automatically.
- Self-Documenting Code: The function
def get_user(user_id: int) -> User:explains itself. You don’t need to read the internal logic to know how to use it. - Faster Coding Speed: IDEs like VS Code or PyCharm provide more accurate code suggestions (IntelliSense). In practice, this helps reduce library documentation look-up time by 40%.
- Catching Hidden Logic Errors: Mypy will warn you if you forget to handle cases where a variable might be
None, helping to avoid random crashes when real-world data doesn’t match expectations.
Important Type Hints
Python’s typing module provides a powerful toolkit for defining complex data structures.
Modern Collections
From Python 3.9 onwards, you should use generic keywords directly instead of importing from the typing library.
names: list[str] = ["Alice", "Bob", "Charlie"]
scores: dict[str, float] = {"Alice": 9.5, "Bob": 8.0}
Handling None with Optional
Optional[T] (or T | None in Python 3.10+) is extremely useful when a function might not find a result.
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
if user_id == 1:
return "Admin"
return None
Any – The Last Resort
Any allows a variable to accept any data type. When first migrating an old project, you can use Any to bypass checks quickly. However, abusing Any will negate the value of Mypy.
Professional Mypy Configuration with pyproject.toml
Typing commands manually is time-consuming. Create a pyproject.toml file to standardize the checking process for the whole team.
[tool.mypy]
python_version = "3.10"
warn_return_any = true
disallow_untyped_defs = true # Force all functions to have type hints
ignore_missing_imports = true # Ignore errors from libraries lacking type hints
Once set up, you only need to run mypy . to scan the entire project.
Experience Applying Mypy to Live Projects
Don’t try to achieve 100% type hint coverage immediately for legacy code. The number of reported errors can reach thousands, which can be discouraging.
Effective implementation roadmap:
- Prioritize new modules: Only apply strict configurations to features currently under development.
- Use
# type: ignore: For overly complex lines of code or non-standard third-party libraries, add this comment for Mypy to skip them. - Block bad code in CI/CD: Integrate Mypy into GitHub Actions. If the check fails, do not allow the code to be merged into the main branch.
Using Mypy is a step forward from writing code that “works” to writing code that is “reliable.” Good luck building more stable Python systems!

