9

if arr = [4,3,2,1] and i want to swap the first value with the minimum of the array , if am using this on python

arr[0] , arr[arr.index(min(arr))] = min(arr) , arr[0] 
#or   
arr[0] , arr[arr.index(min(arr))] = arr[arr.index(min(arr))] , arr[0]

they are not working but if i do this

b = arr.index(min(arr))  
#and then  
arr[0] , arr[b] = arr[b] , arr[0]

this works fine. Can anyone explain why ?

smci
  • 32,567
  • 20
  • 113
  • 146
shailesh bhagat
  • 149
  • 1
  • 8
  • 1
    [Python evaluates expressions left-to-right](https://stackoverflow.com/questions/46288616/is-pythons-order-of-evaluation-of-function-arguments-and-operands-deterministic) – smci Aug 16 '18 at 20:54
  • @smci: Except that it's not actually left-to-right here. It could have been designed to be left-to-right, but it wasn't. (I really wish Python multiple assignment had been designed to evaluate all expressions left-to-right, *then* start assigning things.) – user2357112 Aug 16 '18 at 21:31
  • @user2357112: then please explain what it is. It is parsed left-to-right, then each expression is dynamically evaluated, yes? For a tuple assignment `L1, L2 = R1, R2`, L1 is evaluated first, then R1, then L2, then R2? – smci Aug 16 '18 at 22:07
  • @smci: Nope. R1, R2, L1, (first assignment happens here), L2, (second assignment happens here). – user2357112 Aug 16 '18 at 22:09
  • @user2357112: ok. Please do go ahead and post that as an answer, we need a clear succinct answer. Also, how should [that older Q&A](https://stackoverflow.com/questions/46288616/is-pythons-order-of-evaluation-of-function-arguments-and-operands-deterministic) be corrected? – smci Aug 16 '18 at 22:12
  • 1
    @smci: The older answer mentions the exception for assignments, but in a way that's easy to miss. I've edited it to be a bit more clear. – user2357112 Aug 16 '18 at 22:22
  • Requoting @user2357112: **Python evaluates expressions L-to-R, except for assignments, where the RHS is evaluated before the LHS** – smci Aug 17 '18 at 22:27

1 Answers1

8

It has to do with the order of the operations.

We can subclass lists to instrument them to show what they're doing.

class TracingList(list):
    def __getitem__(self, key):
        value = super().__getitem__(key)
        print(self, "reading", key, "=", value)
        return value

    def __setitem__(self, key, value):
        print(self, "writing", key, "=", value)
        super().__setitem__(key, value)

    def index(self, value):
        index = super().index(value)
        print(self, "finding index of", value, "=", index)
        return index


arr = TracingList([4, 3, 2, 1])
arr[0], arr[arr.index(min(arr))] = min(arr), arr[0]
print(arr)
print("===")

arr = TracingList([4, 3, 2, 1])
arr[0], arr[arr.index(min(arr))] = arr[arr.index(min(arr))], arr[0]
print(arr)
print("===")

arr = TracingList([4, 3, 2, 1])
b = arr.index(min(arr))
arr[0], arr[b] = arr[b], arr[0]
print(arr)

prints out

[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] finding index of 1 = 0
[1, 3, 2, 1] writing 0 = 4
[4, 3, 2, 1]
===
[4, 3, 2, 1] finding index of 1 = 3
[4, 3, 2, 1] reading 3 = 1
[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] finding index of 1 = 0
[1, 3, 2, 1] writing 0 = 4
[4, 3, 2, 1]
===
[4, 3, 2, 1] finding index of 1 = 3
[4, 3, 2, 1] reading 3 = 1
[4, 3, 2, 1] reading 0 = 4
[4, 3, 2, 1] writing 0 = 1
[1, 3, 2, 1] writing 3 = 4
[1, 3, 2, 4]
AKX
  • 152,115
  • 15
  • 115
  • 172
  • 2
    To explain, `arr[0]` gets set before `arr[arr.index(min(arr))]` gets evaluated and set. Thus once `arr[0]` is set to 1, the index of the min becomes 0. So `arr[arr.index(min(arr))]` assigns 4 to index 0. – bjschoenfeld Aug 16 '18 at 20:21
  • This means that if you change the order of the assignments, i.e. `arr = [4,3,2,1]; arr[arr.index(min(arr))], arr[0] = arr[0], min(arr); print(arr)`, you get the "correct" result. :o – Michael H. Aug 16 '18 at 20:29
  • Ok but there's no explanation of what the order of evaluation actually is, or why it is so, or what principle is being followed. This is just like saying *"The order is whatever it is, because it is so"*. **[Python evaluates expressions L-to-R, except for assignments, where the RHS is evaluated before the LHS](https://stackoverflow.com/questions/46288616/is-pythons-order-of-evaluation-of-function-arguments-and-operands-deterministic)** – smci Aug 17 '18 at 22:29