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

PythonSyntaxSwapConventions

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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

Solution 2 - Python

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

Solution 3 - Python

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

Solution 4 - Python

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].

Solution 5 - Python

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 https://stackoverflow.com/questions/14933577/swap-slices-of-numpy-arrays/14933939#14933939

Solution 6 - Python

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.

Solution 7 - Python

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

Solution 8 - Python

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWilliamKFView Question on Stackoverflow
Solution 1 - PythoneyquemView Answer on Stackoverflow
Solution 2 - PythonMartijn PietersView Answer on Stackoverflow
Solution 3 - PythonNoOneIsHereView Answer on Stackoverflow
Solution 4 - PythonYi HuangView Answer on Stackoverflow
Solution 5 - PythongizzmoleView Answer on Stackoverflow
Solution 6 - PythonLogicalBranchView Answer on Stackoverflow
Solution 7 - PythonedWView Answer on Stackoverflow
Solution 8 - Pythonu-betchaView Answer on Stackoverflow