Is there a standardized method to swap two variables in Python?

Question:

In Python, I’ve seen two variable values swapped using this syntax:

left, right = right, left

Is this considered the standard way to swap two variable values or is there some other means by which two variables are by convention most usually swapped?

Asked By: WilliamKF

||

Answers:

That is the standard way to swap two variables, yes.

Answered By: Martijn Pieters

Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.

Python docs: Evaluation order

That means the following for the expression 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)

This mechanism has effectively swapped the objects assigned to the identifiers a and b

So, to answer your question: YES, it’s the standard way to swap two identifiers on two objects.
By the way, the objects are not variables, they are objects.

Answered By: eyquem

I know three ways to swap variables, but a, b = b, a is the simplest. There is

XOR (for integers)

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

Or concisely,

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

Temporary variable

w = x
x = y
y = w
del w

Tuple swap

x, y = y, x
Answered By: NoOneIsHere

I would not say it is a standard way to swap because it will cause some unexpected errors.

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

nums[i] will be modified first and then affect the second variable nums[nums[i] - 1].

Answered By: Yi Huang

Does not work for multidimensional arrays, because references are used here.

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)

See also Swap slices of Numpy arrays

Answered By: gizzmole

To get around the problems explained by eyquem, you could use the copy module to return a tuple containing (reversed) copies of the values, via a function:

from copy import copy

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

Same function as a lambda:

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

Then, assign those to the desired names, like this:

x, y = swapper(y, x)

NOTE: if you wanted to you could import/use deepcopy instead of copy.

Answered By: LogicalBranch

You can combine tuple and XOR swaps: 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))

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

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

Output:

Before swapping: x =  10 , y =  20
After swapping: x =  20 , y =  10
Answered By: u-betcha

That syntax is a standard way to swap variables. However, we need to be careful of the order when dealing with elements that are modified and then used in subsequent storage elements of the swap.

Using arrays with a direct index is fine. For example:

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

Gives us:
(‘For A=’, [0, 1, 2, 3, 4])
(‘A[i1]=’, 3, ‘A[i2]=’, 1)
(‘swap indexes 1, 3:’, [0, 3, 2, 1, 4])

However, if we change the left first element and use it in the left second element as an index, this causes a bad swap.

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])
(‘Before: P[i2]=’, 3, ‘P[P[i2]]=’, 4)
(‘Good swap: 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])

The bad swap is incorrect because P[i2] is 3 and we expect P[P[i2]] to be P[3]. However, P[i2] is changed to 4 first, so the subsequent P[P[i2]] becomes P[4], which overwrites the 4th element rather than the 3rd element.

The above scenario is used in permutations. A simpler good swap and bad swap would be:

#good swap:
P[j], j = j, P[j]
#bad swap:
j, P[j] = P[j], j
Answered By: edW
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.