Аргументы подписи метода типа (self)
Когда я определяю класс, как я могу включить аргументы в сигнатуры его методов, которые должны быть одного и того же класса? Я строю графовую структуру, которая должна работать следующим образом, но вот упрощенный пример:
class Dummy:
def __init__(self, value: int, previous: Dummy=None):
self._value = value
self._previous = previous
@property
def value(self):
return self._value
def plus_previous(self):
return self.value + self._previous.value
d1 = Dummy(7)
d2 = Dummy(3, d1)
d2.plus_previous()
Это приводит к следующей ошибке:
NameError: name 'Dummy' is not defined
Я имею в виду, я могу сделать это с помощью Python 2, но я надеялся, что есть более Python-3-ic решение, чем это:
class Dummy:
def __init__(self, value: int, previous=None):
assert type(previous) is Dummy or previous is None
...
1 ответ
Хотя я согласен, это довольно уродливый хак, вы также можете использовать строки в качестве подсказок типа:
class Dummy:
def __init__(self, value: int, previous: 'Dummy'=None):
self._value = value
self._previous = previous
@property
def value(self):
return self._value
def plus_previous(self):
return self.value + self._previous.value
как описано в PEP-484 на подсказках типа:
Когда подсказка типа содержит имена, которые еще не определены, это определение может быть выражено как строковый литерал, который будет разрешен позже.
Ситуация, в которой это обычно происходит, - это определение класса контейнера, где определяемый класс встречается в сигнатуре некоторых методов. Например, следующий код (начало простой реализации двоичного дерева) не работает:
class Tree: def __init__(self, left: Tree, right: Tree): self.left = left self.right = right
Для решения этой проблемы мы пишем:
class Tree: def __init__(self, left: 'Tree', right: 'Tree'): self.left = left self.right = right
Строковый литерал должен содержать допустимое выражение Python (т. Е.
compile(lit, '', 'eval')
должен быть допустимым объектом кода), и он должен оценивать без ошибок после полной загрузки модуля. Локальное и глобальное пространство имен, в котором оно оценивается, должно быть теми же пространствами имен, в которых будут оцениваться аргументы по умолчанию для одной и той же функции.
Однако проблема с этим хаком заключается в том, что если вы сделаете переименование в IDE, вполне возможно, что IDE не примет во внимание эти строковые литералы и, следовательно, не сможет их переименовать.