Per the documentation:
Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.
For more detail, see this section. There is a good example of a brain-teaser exploiting this behaviour here.
This means that the right-hand side of the =
is evaluated first, left-to-right, then the assignment is made to the left-hand side, left-to-right. Necessarily, the brackets are evaluated inside-out. Breaking that down stepwise, here's the first example:
i = 1
A = [3, 4, -1, 1]
A[A[i] - 1], A[i] = A[i], A[A[i] - 1]
= A[1], A[A[i] - 1]
= 4, A[A[i] - 1]
= 4, A[A[1] - 1]
= 4, A[4 - 1]
= 4, A[3]
= 4, 1
A[A[i] - 1], A[i] = 4, 1
A[A[1] - 1], A[i] = 4, 1
A[4 - 1], A[i] = 4, 1
A[3], A[i] = 4, 1 # A becomes [3, 4, -1, 4]
A[i] = 1
A[1] = 1 # A becomes [3, 1, -1, 4]
And here's the second:
i = 1
A = [3, 4, -1, 1]
A[i], A[A[i] - 1] = A[A[i] - 1], A[i]
= A[A[1] - 1], A[i]
= A[4 - 1], A[i]
= A[3], A[i]
= 1, A[i]
= 1, A[1]
= 1, 4
A[i], A[A[i] - 1] = 1, 4
A[1], A[A[i] - 1] = 1, 4 # A becomes [3, 1, -1, 1]
A[A[1] - 1] = 4
A[1 - 1] = 4
A[0] = 4 # A becomes [4, 1, -1, 1]
The assignment to the left-hand target on the left-hand side alters the content of A
, which changes the indexing in the right-hand target. The 4
is assigned to either A[3]
or A[0]
, depending on the value of A[1]
(which changes from 4
to 1
) when the index is calculated.
"What's the best way to do this kind of multiple assignment in one line?" - I'd do my very best to avoid it. I can't think of any situation where it would be necessary to assign to moving targets like this.