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

left, right = right, left

这被认为是交换两个变量值的标准方法吗?还是有其他方法可以使两个变量按惯例交换?


当前回答

你可以结合元组和异或交换:x, y = x ^ x ^ y x ^ 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))

or

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))

使用λ:

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

其他回答

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

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

首先修改Nums [i],然后影响第二个变量Nums [Nums [i] - 1]。

Python从左到右计算表达式。注意,当 求赋值时,右边在 左手边。 Python文档:计算顺序

这意味着表达式a,b = b,a:

The right-hand side b,a is evaluated, that is to say, a tuple of two elements is created in the memory. The two elements are the objects designated by the identifiers b and a, that were existing before the instruction is encountered during the execution of the program. Just after the creation of this tuple, no assignment of this tuple object has still been made, but it doesn't matter, Python internally knows where it is. Then, the left-hand side is evaluated, that is to say, the tuple is assigned to the left-hand side. As the left-hand side is composed of two identifiers, the tuple is unpacked in order that the first identifier a be assigned to the first element of the tuple (which is the object that was formerly b before the swap because it had name b) and the second identifier b is assigned to the second element of the tuple (which is the object that was formerly a before the swap because its identifiers was a)

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

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

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

使用带有直接索引的数组是可以的。例如:

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) ('swap index 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) ('Good swap: After P[i2]=', 4, 'P[P[i2]]=', 3) ('良好的交换索引2:',[1,2,4,3,5])

('前:P[i2]=', 3, 'P[P[i2]]=', 4) ('错误交换:After P[i2]=', 4, 'P[P[i2]]=', 4) ('与索引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

对多维数组无效,因为这里使用了引用。

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数组的交换片

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

from copy import copy

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

与lambda相同的函数:

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

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

x, y = swapper(y, x)

注意:如果你想,你可以导入/使用deepcopy而不是copy。