- Published on
Using TYPE_CHECKING constant in python
- Authors
- Name
- Ismail Tlemcani
- @Ismailtlem
Below is a small article in order to better understand the usage of the TYPE_CHECKING constant in Python
Typing in Python ?
As we know that Python is a dynamic language, which means it only checks the types of the variables you specified at runtime. You can read more details about that in this very well written article.
But we can add type hints to a Python code, and it's more and more used. The benefits of doing so are :
- Better code readability.
- Data validation by using tools like Pydantic
- Catching bugs related to the types of variables early with the help of tools like mypy
Type hints are not necessary, and some Python programmers still prefer to not use them, but I do think it's a good habit to have and it's even officially encouraged because of the gradual integration of python types like list and dict in recent Python versions.
TYPE_CHECKING constant ?
It's a constant defined in the typing module that is False at runtime and True while type checking with a type checker like mypy. We usually put the code that we don't want to be executed at runtime inside if TYPE_CHECKING: condition
When should we use that ?
Since code inside if TYPE_CHECKING: is not executed at runtime, this is a convenient way to send some information to the type checker without the code being evaluated at runtime.
One usage of TYPE_CHECKING constant is resolving some circular import errors (module A imports module B and module B imports module A) caused by adding some type annotations
Example ?
Consider this file a.py
from b import B
def f(b: B) -> None:
b.say_hello()
def g() -> None:
print("hello world from g")
and this file b.py
from a import g
import sys
class B:
def say_hello(self) -> None:
g()
if __name__ == "__main__":
b = B()
b.say_hello()
sys.exit()
Running the b.py file will result in a circular import error
Using TYPE_CHECKING
- First import TYPE_CHECKING constant from typing
- If you are using python 3.6 and below, you can just enter the problematic type as a string
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from b import B
def f(b: 'B') -> None:
b.say_hello()
def g() -> None:
print("hello world from g")
- If you are using Python 3.7 and up, you can just import annotations from future module to resolve this:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from b import B
def f(b: B) -> None:
b.say_hello()
def g() -> None:
print("hello world from g")
Running the b.py file will now be successful and result in printing the sentence hello world from g