Python multiple assignment issue (list) [duplicate]

此生再无相见时 提交于 2019-11-28 14:15:50
jonrsharpe

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.

With how you're encouraged to do things like a, b = b, a+b, you might think that multiple assignments like this are supposed to always bypass problems with one assignment interfering with another. Particularly, it's natural to think that all expression evaluations happen before any assignments. Unfortunately, that's not how it works.

When you have a multiple assignment of the form

expr_a[expr_b], expr_c[expr_d] = expr_e, expr_f

the order of events goes as follows:

  1. Evaluate the right-hand side, evaluating expr_e and expr_f.
  2. Perform the first assignment, evaluating expr_a and expr_b.
  3. Perform the third assignment, evaluating expr_c and expr_d. The first assignment has already happened when these expressions are evaluated.

That means that if assigning to expr_a[expr_b] changes the value of expr_c or expr_d, that will change what happens in the second assignment.

In your case, assigning to A[i] changes the value of A[i] - 1 in the assignment target A[A[i] - 1].


Don't use a multiple assignment in cases like this. Separate the assignments onto their own lines, and use temporary variables if necessary to remember values that get changed by assignments.

The sequence of operations works the same for any multiple assignment:

  1. Evaluate every expression on the RHS (right-hand side), left to right, placing each into a temporary variable.
  2. Evaluate the expressions on the LHS (left), left to right. For each of these, assign the corresponding temporary variable from the RHS.

For your code, this expands to:

# A[A[i] - 1], A[i]  =  A[i], A[A[i] - 1]
A = [3,4,-1,1]
t1 = A[i]
t2 = A[A[i] - 1]
# t1 = 4, t2 = 1
A[A[i] - 1] = t1
A[i] = t2
print A
# Result: [3, 1, -1, 4]

# A[i], A[A[i] - 1] = A[A[i] - 1], A[i]
A = [3,4,-1,1]
t2 = A[A[i] - 1]
t1 = A[i]
# As before, t1 = 4, t2 = 1
A[i] = t2
# A[i] is now 1 !
A[A[i] - 1] = t1
print A
# Result: [4, 1, -1, 1]

The critical difference is when A[i] gets changed in each sequence. IN the second example, when we evaluate A[A[i] - 1] in the final assignment, A[i] has already changed to 1. Therefore, this last assignment puts 4 into location 0, rather than location 3.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!