Python type annotations on classes
You can’t normally access the class itself inside the class’ function declarations (because the class hasn’t been finished declaring itself yet, because you’re still declaring its methods).
So something like this isn’t valid Python:
class MyClass:
def __init__(self, x: str) -> None:
self.x = x
def copy(self) -> MyClass:
copied_object = MyClass(x=self.x)
return copied_object
Solutions
There’s two ways to fix this.
Strings for classnames
Turn the classname into a string: The creators of PEP 484 and Mypy knew that such cases exist where you might need to define a return type which doesn’t exist yet. So, mypy is able to check types if they’re wrapped in strings.
class MyClass:
def __init__(self, x: str) -> None:
self.x = x
def copy(self) -> 'MyClass':
copied_object = MyClass(x=self.x)
return copied_object
Postponed evaluation of type annotations
Use from __future__ import annotations
. What this does, is turn on a new feature in Python called “postponed evaluation of type annotations”. This essentially makes Python treat all type annotations as strings, storing them in the internal __annotations__
attribute. Details are described in PEP 563.
from __future__ import annotations
class MyClass:
def __init__(self, x: str) -> None:
self.x = x
def copy(self) -> MyClass:
copied_object = MyClass(x=self.x)
return copied_object
Info
Starting with Python 3.11, the Postponed evaluation behaviour will become default, and you won’t need to have the __future__
import anymore.
Credits
Most of the contents in this note were copied verbatim from Tushar Sadhwani’s The Comprehensive Guide to Mypy.