【问题标题】:python swaping values using comma is causing confusionspython使用逗号交换值导致混乱
【发布时间】:2019-04-25 13:23:35
【问题描述】:

这涉及到我在尝试解决链表反向问题时遇到的问题。

先放一些链表定义的初步代码和快速生成链表的方法:

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

    def __repr__(self):
        if self.next:
            return "{}->{}".format(self.val, repr(self.next))
        else:
            return "{}".format(self.val)

def genNode(*nodes, end=None):
    if len(nodes) == 1 and type(nodes[0]) == list:
        nodes = nodes[0]
    for i in nodes[::-1]:
        n = ListNode(i)
        n.next, end = end, n
    return n if nodes else None

我的问题是我发现交换机制仍然取决于我写的变量的顺序。

最初当我们谈论在 python 中交换值时,我们可以这样做:

a, b = b, a

如果我有,它应该以同样的方式工作

b, a = a, b

我正在尝试写的这个反向链表方法有3个变量交换,想法很简单,创建一个dummy head,并在dummy和dummy.next之间不断添加节点,以便它可以反转。

def rev(head):
    dummy = ListNode('X')
    while head:
        dummy.next, head.next, head = head, dummy.next, head.next
    return dummy.next

a = genNode(1,2,3,4)
print(rev(a)) # >>> 4->3->2->1

但如果我稍微切换3个变量的顺序:

def rev2(head):
    dummy = ListNode('X')
    while head:
        dummy.next, head, head.next, = head, head.next, dummy.next,
    return dummy.next

a = genNode(1,2,3,4)
print(rev2(a))  # >>> AttributeError: 'NoneType' object has no attribute 'next'

所以看起来顺序在这里很重要,如果有超过 2 个变量,任何人都可以告诉我 python 如何评估交换值。

谢谢!

【问题讨论】:

  • 哪个版本的python?
  • 是python 3.6.4
  • 真的,别那样做。 a, b = b, a 适用于简单的交换,但对于更复杂的,只需编写单独的赋值语句即可。
  • 您要交换的数据类型不是简单的基本数据类型,而是一个涉及到其他对象链接的类对象,这可能会导致此类意外行为!
  • @chepner 我打算从现在开始这样做。我不知道这会发生。一直认为一切都是同时评估的。

标签: python python-3.x swap


【解决方案1】:

从左到右

https://docs.python.org/3/reference/simple_stmts.html#assignment-statements

CPython 实现细节:在当前实现中,target 的语法与表达式的语法相同,在代码生成阶段拒绝无效语法,导致错误消息的详细程度较低。

虽然赋值的定义意味着左侧和右侧之间的重叠是“同时的”(例如 a, b = b, a 交换两个变量),但在赋值对象的集合中重叠变量从左到右出现,有时会导致混淆。例如,下面的程序打印 [0, 2]:

x = [0, 1]
i = 0
i, x[i] = 1, 2         # i is updated, then x[i] is updated
print(x)

【讨论】:

  • 将其与 OP 的示例联系起来:在rev() 中,head 被更改之后 head.next 被分配到;在rev2 中,head 被更改之前,从而改变了分配给的内容。
  • 这很有趣,如果我尝试x[i], i = 2, 1 ,它实际上会起作用。所以顺序很重要,但可能会令人困惑。
  • 那么,(C)Python 遍历 RHS 上的值的 tuple 并将它们分配给 LHS 上的名称 tuple,按元素顺序排列?如果你把逗号分隔的列表解释为tuple,这个作案手法似乎很合乎逻辑。
  • 那么您是否建议,当遇到复杂/多个交换情况时,我应该通过创建临时变量来回到经典交换方法,以确保安全?
  • 类似于不更改您正在迭代的list,您可能应该避免分配可能影响同一赋值语句中其他赋值的名称,如示例中所示。这个例子非常构建,我从来没有见过这样的代码。
【解决方案2】:

下面的一个简单示例应该向您展示使用像 ListNode 这样的类交换的注意事项

让我们定义一个 3 元素的链表。

a = ListNode(1)
b = ListNode(2)
c = ListNode(3)
a.next = b
b.next = c
print(a)
#1->2->3

现在如果我们交换 b 和 c,它不会有任何效果

b,c = c,b
print(a)
#1->2->3

如果我们交换 a 和 b,链表就会改变。

a,b=b,a
print(a)
#2->3

a 和 c 交换也是如此。

a,c=c,a
print(a)
#3

因此您可以看到,使用简单交换逻辑在应用于ListNode 的方式上是不一致的,因此应该避免。

【讨论】:

  • 谢谢,这是一个很好的示范。我应该避免在复杂的数据结构中使用交换方法。
  • 太好了,如果它对您有帮助,请考虑支持该示例,因为您已经接受了另一个答案!
【解决方案3】:

如果有两个以上的变量,它的工作方式与两个相同。您将它们按所需的最终顺序排列:

>>> a = 1
>>> b = 2
>>> c = 3
>>> c,b,a = a,b,c
>>> a,b,c
(3, 2, 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    相关资源
    最近更新 更多