Python 逗号赋值顺序

Python comma assignments order

我正在尝试 Python 逗号赋值来并行更改变量的值。我相信 Python 会首先评估右侧表达式的值,然后将这些值分配给左侧的变量。一个具体的例子是在这个反向链表代码中:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        prev = None
        curr = head
        while curr != None:
            prev, curr.next, curr = curr, prev, curr.next
        return prev

prev, curr.next, curr = curr, prev, curr.next 工作得很好。如果我将顺序更改为 prev, curr, curr.next = curr, curr.next, prev,我希望我的代码能正常工作:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        prev = None
        curr = head
        while curr != None:
            prev, curr, curr.next = curr, curr.next, prev
        return prev

但是,我在该行的第二个代码中得到了一个错误:

AttributeError: 'NoneType' object has no attribute 'next'
    prev, curr, curr.next = curr, curr.next, prev

这对我来说没有意义,因为 Python 在赋值之前首先计算右侧的表达式,这意味着我放置表达式的顺序无关紧要。我在这里遗漏了什么吗?

Python 先计算右边是正确的;但是,缺少的是 Python 将按顺序 评估每一面 。我们可以通过将两个选项分解为单独的赋值语句 (Full example on Hastebin):

来了解这意味着什么
# First example:
def reverseList(head: ListNode) -> ListNode:
    prev = None
    curr = head
    while curr != None:
        # prev, curr.next, curr = curr, prev, curr.next
        x = curr
        y = prev
        z = curr.next
        prev = x
        curr.next = y
        curr = z
    return prev
# Second example:
def reverseList2(head: ListNode) -> ListNode:
    prev = None
    curr = head
    while curr != None:
        # prev, curr, curr.next = curr, curr.next, prev
        x = curr
        y = curr.next
        z = prev
        prev = x
        curr = y
        curr.next = z
    return prev

这里的重要部分是,在第一个示例中,我们在之前分配curr.next 的值,我们分配curr的值,而在第二个例子我们赋值curr.next之后。这意味着当我们去赋值 curr.next 时,我们已经更新了 curr,所以当解释器再次访问 curr.next 进行另一个赋值时,它会拉回错误的引用。当您将 curr 设置为 None,然后在这样做之后,您尝试访问 curr.next 以完成重新分配操作时,就会发生错误。

旁注,尽量避免使用 next 作为变量名。由于它是一个内置函数,因此可能会引起一些混乱,尽管它可能没问题。