I have the following code in Python 3:
class Position:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __add__(self, other: Position) -> Position:
return Position(self.x + other.x, self.y + other.y)
But my editor (PyCharm) says that the reference Position
can not be resolved (in the __add__
method). How should I specify that I expect the return type to be of type Position
?
I think this is actually a PyCharm issue. It actually uses the information in its warnings, and code completion.
But correct me if I'm wrong, and need to use some other syntax.
Best Answer
TL;DR: As of today (2019), in Python 3.7+ you can turn this feature on using a "future" statement,
from __future__ import annotations
.(The behaviour enabled by
from __future__ import annotations
might become the default in future versions of Python, and was going to be made the default in Python 3.10. However, the change in 3.10 was reverted at the last minute, and now may not happen at all. Python 3.11 does not include it)In Python 3.6 or below, you should use a string.
I guess you got this exception:
This is because
Position
must be defined before you can use it in an annotation, unless you are using Python with PEP 563 changes enabled.Python 3.11+:
from typing import Self
For Python versions < 3.11, you can use:
References:
Python 3.7+:
from __future__ import annotations
Python 3.7 introduces PEP 563: postponed evaluation of annotations. A module that uses the future statement
from __future__ import annotations
will store annotations as strings automatically:This had been scheduled to become the default in Python 3.10, but this change has now been postponed. Since Python still is a dynamically typed language so no type-checking is done at runtime, typing annotations should have no performance impact, right? Wrong! Before Python 3.7, the typing module used to be one of the slowest python modules in core so for code that involves importing the
typing
module, you will see an up to 7 times increase in performance when you upgrade to 3.7.Python <3.7: use a string
According to PEP 484, you should use a string instead of the class itself:
If you use the Django framework, this may be familiar, as Django models also use strings for forward references (foreign key definitions where the foreign model is
self
or is not declared yet). This should work with Pycharm and other tools.Sources
The relevant parts of PEP 484 and PEP 563, to spare you the trip:
and PEP 563:
Things that you may be tempted to do instead
A. Define a dummy
Position
Before the class definition, place a dummy definition:
This will get rid of the
NameError
and may even look OK:But is it?
B. Monkey-patch in order to add the annotations:
You may want to try some Python metaprogramming magic and write a decorator to monkey-patch the class definition in order to add annotations:
The decorator should be responsible for the equivalent of this:
At least it seems right:
Probably too much trouble.