The replacement of the two values isn't truly simultaneous; they are handled in order from left to right. So altering arr
during that process is leading to this behavior.
Consider this alternative example:
>>> arr = [1, 2, 3]
>>> arr[0], arr[arr[0]] = 10, 5
...
With a hypothetical simultaneous reassignment, we try to replace the first value of arr
with 10
, and then the arr[0]
th (aka 1
st) element with 5
. So hopefully, we get [10, 5, 3]
. But this fails with IndexError: list assignment index out of range
. If you then inspect arr
after this error:
>>> arr
[10, 2, 3]
The first assignment was completed, but the second failed. When it came to the second assignment (after the comma), the actual arr[0]
th (aka 10
th) value cannot be found (b/c the list isn't that long).
This behavior can also be seen by clearly specifying the second assignment to fail (still by specifying an index out of range):
>>> arr = [1, 2, 3]
>>> arr[0], arr[99] = 5, 6
# Same index error, but arr becomes [5, 2, 3]
This feels reminiscent of modifying a list you are iterating over, which is sometimes doable but often discouraged because it leads to issues like what you are seeing.
One alternative is to create a copy (this is sometimes a solution for modifying the list you are iterating over), and use that for referencing values in arr
:
>>> arr = [4, 2, 1, 3]
>>> copy = arr.copy()
>>> arr[0], arr[copy[0]-1] = copy[copy[0]-1], copy[0]
>>> arr
[3, 2, 1, 4]
Though it is pretty ugly here. The alternative in the accepted answer is much nicer, or this idiomatic approach should probably work as well!