TYPE_CHECKING
Imagine you have a case where you have a circular dependency. Usually, this is a problem, and a quick post on interface stubs may be helpful, but sometimes refactoring it wouldn't make sense, and the circular import may not be practical to refactor.
Instead, what you may do is use TYPE_CHECKING:
from __future__ import annotations # optional but handy for forward refs
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# Only imported for type checkers; not executed at runtime
from some_heavy_lib import BigType
class Thing:
def __init__(self, x: BigType): # works for type checkers
self.x = x
The TYPE_CHECKING constant is False at runtime
but True
when type checkers like mypy or PyCharm analyze your code. This means imports
inside the
if TYPE_CHECKING: block are only processed during static type
checking.
This pattern is useful for several scenarios:
Avoiding circular imports: When two modules need to reference each other's types, you can break the cycle by importing one side only for type checking.
# user.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from order import Order
class User:
def __init__(self, name: str):
self.name = name
self.orders: list[Order] = []
# order.py
from user import User
class Order:
def __init__(self, user: User, amount: float):
self.user = user
self.amount = amount
Skipping heavy dependencies: Import expensive libraries only for type hints without the runtime overhead.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import pandas as pd
import numpy as np
def process_data(df: pd.DataFrame) -> np.ndarray:
# pandas and numpy aren't imported at runtime
# but type checkers understand the annotations
pass
Clean annotations: Keep type annotations readable without string literals or complex workarounds.
# Instead of this:
def bad_example(data: "ComplexType") -> "list[ComplexType]":
pass
# You can write this:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from complex_module import ComplexType
def good_example(data: ComplexType) -> list[ComplexType]:
pass
TYPE_CHECKING is essential when you need to reference types that
would cause circular imports, performance issues, or dependency problems, while
still maintaining excellent static type checking support.
Questions or feedback? Feel free to reach out!