About Postponed Evaluation of Annotations
Let's say you're working on a Django project, and you have a model with a custom create method on the manager:
# managers.py
class MyManager:
def create(self):
# your custom logic here
return super().create()
# models.py
from .managers import MyManager
class MyModel:
objects = MyManager()
So far, so good. But now what if you need access to MyModel
inside managers.py
? You can't import it directly due to circular imports. You could just inline the import, but what if you don't like that? You want all your imports at the top of your file, in global scope. self.model
to the rescue!
# managers.py
class MyManager:
def create(self):
# self.model here is equivalent to MyModel
self.model.do_a_thing()
return super().create()
But now what if you want to include type annotations on your manager method? create
returns the created model instance, so...
# managers.py
class MyManager:
def create(self) -> self.model: # THIS DOES NOT WORK
self.model.do_a_thing()
return super().create()
Can't do that! So now what?
PEP 563 to the rescue! Turns out the typing
module has a fancy constant: TYPE_CHECKING
:
# managers.py
from __future__ import annotations # if pre-3.10
import typing
if typing.TYPE_CHECKING:
from .models import MyModel
class MyManager:
def create(self) -> MyModel: # hooray!
self.model.do_a_thing()
return super().create()
TYPE_CHECKING
is true only when type checking. It works with your IDE (probably), it works with mypy
-- but it's false at runtime. No circular imports, no inline imports, and all the benefits of type hints!