How does mypy use typing.TYPE_CHECKING to resolve the circular import annotation problem?
How does mypy use typing.TYPE_CHECKING to resolve the circular import annotation problem?
--
Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn
--
Track title: CC F Haydns String Quartet No 53 in D
--
Chapters
00:00 Question
03:17 Accepted answer (Score 19)
06:03 Thank you
--
Full question
https://stackoverflow.com/questions/6154...
Question links:
[TYPE_CHECKING docs]: https://docs.python.org/3/library/typing...
[mypy docs]: https://mypy.readthedocs.io/en/stable/co...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #import #annotations #typehinting #mypy
#avk47
ACCEPTED ANSWER
Score 32
Does the process of "type checking" mean code is not executed?
Yes, exactly. The type checker never executes your code: instead, it analyzes it. Type checkers are implemented in pretty much the same way compilers are implemented, minus the "generate bytecode/assembly/machine code" step.
This means your type checker has more strategies available for resolving import cycles (or cycles of any kind) than the Python interpreter will have during runtime since it doesn't need to try blindly importing modules.
For example, what mypy does is basically start by analyzing your code module-by-module, keeping track of each new class/new type that's being defined. During this process, if mypy sees a type hint using a type that hasn't been defined yet, substitute it with a placeholder type.
Once we've finished checking all the modules, check and see if there are still any placeholder types floating around. If so, try re-analyzing the code using the type definitions we've collected so far, replacing any placeholders when possible. We rinse and repeat until there are either no more placeholders or we've iterated too many times.
After that point, mypy assumes any remaining placeholders are just invalid types and reports an error.
In contrast, the Python interpreter doesn't have the luxury of being able to repeatedly re-analyze modules like this. It needs to run each module it sees, and repeatedly re-running modules could break some user code/user expectations.
Similarly, the Python interpreter doesn't have the luxury of being able to just swap around the order in which we analyze modules. In contrast, mypy can theoretically analyze your modules in any arbitrary order ignoring what imports what -- the only catch is that it'll just be super inefficient since we'd need lots of iterations to reach fixpoint.
(So instead, mypy uses your imports as suggestions to decide in which order to analyze modules. For example, if module A directly imports module B, we probably want to analyze B first. But if A imports B behind if TYPE_CHECKING, it's probably fine to relax the ordering if it'll help us break a cycle.)