我正在编写简单的代码来反转链表,并意识到可以在一行上完成分配,我发现这很酷:
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。我看不出第一个例子和第二个例子有什么区别。我错过了一些简单的事情吗?
有谁知道为什么第一个示例运行而第二个示例产生错误?
是的,元组赋值首先评估右侧(从左到右),然后执行赋值,也从左到右。
来自赋值语句文档:
赋值语句计算表达式列表(请记住,这可以是单个表达式或逗号分隔的列表,后者生成一个元组),并将单个结果对象从左到右分配给每个目标列表。
在第二种情况下,您将
None
分配给 curr_node
,因此下一次对 curr_node.next
的分配失败。
换句话说,这是有效的:
prev_node, curr_node.next, curr_node = curr_node, None, None
(执行
curr_node
时,假设 next
仍然是具有 curr_node.next = None
属性的 Node 实例),但如果交换参数:
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'