Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Порядок операций для трех (или более) различных назначений переменных с использованием связанного списка в python 3

Автор вопроса: Evan ParrishОтветов: 1

Я пишу простой код для реверсирования связанного списка и понял, что присваивания можно выполнять в одной строке, что мне показалось довольно крутым:

    def Reverse(head):
      prev_node = None
      curr_node = head

      while curr_node:
        prev_node, curr_node.next, curr_node = curr_node, prev_node, curr_node.next

      return prev_node

Но я заметил, что код дает сбой, если я изменяю порядок назначений между curr_node.next в левой части (соответствует prev_node в правой части) и curr_node в левой части (...curr_node.next в правой части)

    def Reverse(head):
      prev_node = None
      curr_node = head
      print(curr_node.data)
      print(curr_node.next.data)
      print(prev_node)

      while curr_node:
        prev_node, curr_node, curr_node.next = curr_node, curr_node.next, prev_node

      return prev_node

Вход

1 2 3 4

Выход

1
2
None

Но из цикла while возникает следующая ошибка (только во втором блоке кода, первый работает нормально)

      prev_node, curr_node, curr_node.next = curr_node, curr_node.next, prev_node
    AttributeError: 'NoneType' object has no attribute 'next'

Самое близкое обсуждение, которое я смог найти по этому вопросу, было здесь. Что говорит о том, что RHS сначала оценивается слева направо. Я думаю, это означает, что хранится curr_node, затем prev_node, затем curr_node.next. Затем они назначаются prev_node, curr_node.next и curr_node соответственно. Я не вижу разницы между первым и вторым примером. Я пропустил что-то простое?

Кто-нибудь знает, почему первый пример запускается, а второй выдает ошибку?

pythonvariable-assignmentiterable-unpacking

Ответы

Ответ 1 · рейтинг 3 · Martijn Pieters

Да, при присвоении кортежа сначала оценивается правая сторона (слева направо), и присваивание выполняется также слева направо.

Из документации по операторам присваивания. :

Оператор присваивания оценивает список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, последний дает кортеж) и присваивает единственный результирующий объект каждому из целевых списков слева направо.

Во втором случае вы присвоили None curr_node, поэтому следующее назначение curr_node.next не выполняется.

Другими словами, это работает:

prev_node, curr_node.next, curr_node = curr_node, None, None

(при условии, что curr_node по-прежнему является экземпляром Node с атрибутом next, когда выполняется curr_node.next = None), но если вы поменяете аргументы:

prev_node, curr_node, curr_node.next = curr_node, None, None

и теперь curr_node = None выполняется раньше curr_node.next = prev_node.

Вот упрощенная демонстрация, показывающая порядок выполнения заданий:

>>> class Node:
...     next = None
...
>>> curr_node = Node()
>>> curr_node.next, curr_node = None, None  # first attribute, then name
>>> curr_node = Node()
>>> curr_node, curr_node.next = None, None  # first the name, no attribute anymore
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'next'

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы