Аргументы подписи метода типа (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 не примет во внимание эти строковые литералы и, следовательно, не сможет их переименовать.

Другие вопросы по тегам