Использование класса в качестве типа подсказки для аргументов в его методах
В приведенном ниже коде приведена следующая ошибка:
NameError: name 'Vector2' is not defined
в этой строке:
def Translate (self, pos: Vector2):
Почему Python не распознает мой класс Vector2
в методе Translate
?
class Vector2:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def Translate(self, pos: Vector2):
self.x += pos.x
self.y += pos.y
Ответы
Ответ 1
Поскольку, когда он встречает Translate
(при компиляции тела класса), Vector2
еще не был определен (в настоящее время он компилируется, привязка имени не была выполнена); Питон естественно жалуется.
Поскольку это такой распространенный сценарий (намеки на тип класса в теле этого класса), вы должны использовать прямую ссылку на него, заключив его в кавычки:
class Vector2:
# __init__ as defined
def Translate(self, pos: 'Vector2'):
self.x += pos.x
self.y += pos.y
Python (и любые контролеры, соответствующие PEP 484
) поймут вашу подсказку и зарегистрируют ее соответствующим образом. Python распознает это, когда к __annotations__
обращаются через typing.get_type_hints
:
from typing import get_type_hints
get_type_hints(Vector2(1,2).Translate)
{'pos': __main__.Vector2}
Это было изменено с Python 3.7; см. ответ abarnert ниже.
Ответ 2
Функция, которую вы запрашиваете, называется прямой (типовой) ссылкой, и она была добавлена в Python с версии 3.7 (в PEP 563). 1 Так что теперь это действительно так:
from __future__ import annotations
class C:
def spam(self, other: C) -> C:
pass
Обратите внимание на утверждение __future__
. Это будет необходимо до версии 4.0.
К сожалению, в Python 3.6 и более ранних версиях эта функция недоступна, поэтому вы должны использовать строковые аннотации, как описано в ответе Джима Фасаракиса Хиллиарда.
Mypy уже поддерживает предварительные объявления, даже при запуске под Python 3.6 - но это не принесет вам большой пользы, если средство проверки статического типа говорит, что ваш код в порядке, но интерпретатор вызывает NameError
, когда вы пытаетесь запустить его на самом деле.
1. Это уже обсуждалось в качестве возможной функции в PEP 484, но откладывалось на потом, после того, как у людей появилось больше опыта использования предварительных объявлений в аннотациях. PEP 563/Python 3.7 - это "позже".