python 3 中使用链表的三个(或更多)不同变量赋值的操作顺序

Order of operations for three (or more) distinct variable assignments using a linked list in python 3

我正在编写简单的代码来反转链表,并意识到赋值可以在一行上完成,我觉得这很酷:

    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

但是我注意到,如果我颠倒 LHS 上的 curr_node.next(对应于 RHS 上的 prev_node)和 LHS 上的 curr_node 之间的分配顺序,代码将失败( ...curr_node.next 在 RHS 上)

    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。我看不出第一个和第二个例子之间的区别。我错过了一些简单的东西吗?

有谁知道为什么第一个示例运行而第二个示例产生错误?

是的,元组赋值首先计算右侧(从左到右),然后执行赋值,从左到右。

来自Assignment statements documentation

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

在您的第二种情况下,您将 None 分配给 curr_node,因此下一次分配给 curr_node.next 失败。

换句话说,这个有效:

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

(前提是 curr_node 在执行 curr_node.next = None 时仍然是具有 next 属性的 Node 实例),但是如果交换参数:

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

现在 curr_node = Nonecurr_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'