402

在 Python 中,我看到使用这种语法交换了两个变量值:

left, right = right, left

这是否被认为是交换两个变量值的标准方法,还是有一些其他方法可以按照惯例最常交换两个变量?

4

8 回答 8

482

Python 从左到右计算表达式。请注意,在评估分配时,右侧先于左侧评估。

Python 文档:评估顺序

这意味着表达式的以下内容a,b = b,a

  • 右边b,a是求值的,也就是说,在内存中创建了两个元素的元组。这两个元素是由标识符b和指定的对象a,它们在程序执行期间遇到指令之前就已经存在。
  • 就在这个元组创建之后,还没有对这个元组对象进行赋值,不过没关系,Python内部知道它在哪里。
  • 然后,对左侧进行求值,也就是说,将元组分配给左侧。
  • 由于左侧由两个标识符组成,因此对元组进行解包,以便将第一个标识符a分配给元组的第一个元素(这是在交换之前以前是bb的对象,因为它有 name )
    和第二个标识符b被分配给元组的第二个元素(这是在交换之前以前是 aa的对象,因为它的标识符是)

这种机制有效地交换了分配给标识符的对象ab

所以,回答你的问题:是的,这是在两个对象上交换两个标识符的标准方法。
顺便说一句,对象不是变量,它们是对象。

于 2013-02-12T15:56:33.150 回答
123

这是交换两个变量的标准方法,是的。

于 2013-02-12T15:44:22.827 回答
42

我知道交换变量的三种方法,但a, b = b, a最简单。有

XOR(整数)

x = x ^ y
y = y ^ x
x = x ^ y

或者简而言之,

x ^= y
y ^= x
x ^= y

临时变量

w = x
x = y
y = w
del w

元组交换

x, y = y, x
于 2016-01-06T23:34:40.287 回答
32

我不会说这是一种标准的交换方式,因为它会导致一些意想不到的错误。

nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]

nums[i]会先修改再影响第二个变量nums[nums[i] - 1]

于 2016-12-07T21:10:58.263 回答
6

不适用于多维数组,因为这里使用了引用。

import numpy as np

# swaps
data = np.random.random(2)
print(data)
data[0], data[1] = data[1], data[0]
print(data)

# does not swap
data = np.random.random((2, 2))
print(data)
data[0], data[1] = data[1], data[0]
print(data)

另见交换 Numpy 数组的切片

于 2017-12-06T08:50:08.407 回答
0

为了解决eyquem解释的问题,您可以使用该copy模块通过函数返回一个包含值的(反转)副本的元组:

from copy import copy

def swapper(x, y):
  return (copy(y), copy(x))

与 a 相同的功能lambda

swapper = lambda x, y: (copy(y), copy(x))

然后,将它们分配给所需的名称,如下所示:

x, y = swapper(y, x)

注意:如果您愿意,可以导入/使用deepcopy而不是copy.

于 2019-04-28T16:33:33.203 回答
0

该语法是交换变量的标准方法。但是,在处理被修改然后在交换的后续存储元素中使用的元素时,我们需要注意顺序。

使用带有直接索引的数组很好。例如:

def swap_indexes(A, i1, i2):
      A[i1], A[i2] = A[i2], A[i1]
      print('A[i1]=', A[i1], 'A[i2]=', A[i2])
      return A

  A = [0, 1, 2, 3, 4]
  print('For A=', A)
  print('swap indexes 1, 3:', swap_indexes(A, 1, 3))

给我们:
('For A=', [0, 1, 2, 3, 4])
('A[i1]=', 3, 'A[i2]=', 1)
('交换索引 1, 3 :', [0, 3, 2, 1, 4])

但是,如果我们改变左边的第一个元素并在左边的第二个元素中使用它作为索引,这会导致错误的交换。

def good_swap(P, i2):
    j = P[i2]
    #Below is correct, because P[i2] is modified after it is used in P[P[i2]]
    print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
    P[P[i2]], P[i2] = P[i2], P[P[i2]]
    print('Good swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
    return P

def bad_swap(P, i2):
    j = P[i2]
    #Below is wrong, because P[i2] is modified and then used in P[P[i2]]
    print('Before: P[i2]=', P[i2], 'P[P[i2]]=', P[j])
    P[i2], P[P[i2]] = P[P[i2]], P[i2]
    print('Bad swap: After P[i2]=', P[i2], 'P[P[i2]]=', P[j])
    return P

P = [1, 2, 3, 4, 5]
print('For P=', P)
print('good swap with index 2:', good_swap(P, 2))
print('------')
P = [1, 2, 3, 4, 5]
print('bad swap with index 2:', bad_swap(P, 2))

('For P=', [1, 2, 3, 4, 5])
('之前:P[i2]=', 3, 'P[P[i2]]=', 4)
('好的交换: After P[i2]=', 4, 'P[P[i2]]=', 3)
('good swap with index 2:', [1, 2, 4, 3, 5])

('Before: P[i2]=', 3, 'P[P[i2]]=', 4)
('Bad swap: After P[i2]=', 4, 'P[P[i2]]= ', 4)
('bad swap with index 2:', [1, 2, 4, 4, 3])

坏交换是不正确的,因为 P[i2] 是 3,我们期望 P[P[i2]] 是 P[3]。但是P[i2]先变成了4,所以后面的P[P[i2]]变成了P[4],覆盖的是第4个元素而不是第3个元素。

上述场景用于排列。一个更简单的好交换和坏交换将是:

#good swap:
P[j], j = j, P[j]
#bad swap:
j, P[j] = P[j], j
于 2022-01-01T03:40:02.497 回答
-3

您可以组合元组XOR交换:x, y = x ^ x ^ y, x ^ y ^ y

x, y = 10, 20

print('Before swapping: x = %s, y = %s '%(x,y))

x, y = x ^ x ^ y, x ^ y ^ y

print('After swapping: x = %s, y = %s '%(x,y))

或者

x, y = 10, 20

print('Before swapping: x = %s, y = %s '%(x,y))

print('After swapping: x = %s, y = %s '%(x ^ x ^ y, x ^ y ^ y))

使用lambda

x, y = 10, 20

print('Before swapping: x = %s, y = %s' % (x, y))

swapper = lambda x, y : ((x ^ x ^ y), (x ^ y ^ y))

print('After swapping: x = %s, y = %s ' % swapper(x, y))

输出:

Before swapping: x =  10 , y =  20
After swapping: x =  20 , y =  10
于 2020-01-31T23:31:31.860 回答