1

I recently answered a question where a user was having trouble because they were appending a multi-dimensional array to another array, and it was brought to my attention in my answer that it is possible to use iterable unpacking to populate an x and y value and assign to board[x][y] on the same line.

I had expected this to throw an error as x and y had at the time not been defined, as, even in the iterable-unpacking tag it reads:

elements of an iterable are simultaneously assigned to multiple values

This can be seen as working in the following example:

>>> board = [[0, 0], [0, 0]]
>>> move = [0, 1, 2]
>>> x, y, board[x][y] = move
>>> board
[[0, 2], [0, 0]]

Which is the same as:

>>> board = [[0, 0], [0, 0]]
>>> move = [0, 1, 2]
>>> x = move[0]
>>> y = move[1]
>>> board[x][y] = move[2]
>>> board
[[0, 2], [0, 0]]

And yet when calculating the Fibonacci sequence using:

a, b = b, a + b

It doesn't evaluate as:

a = b
b = a + b

And when swapping values with:

a, b = b, a

It doesn't evaluate as:

a = b
b = a

So why does this work in the first example?

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
  • These examples don't seem to be equivalent. I mean, in the first example, you have ` = `. The second examples tries to involve the same variables on both sides of the `=`. – larsks Dec 16 '17 at 04:09
  • 1
    I think using "Asynchronous" in the title is a bit off the topic of the question and may lead people searching for python `async` in the wrong direction. perhaps something more like "Iterable unpacking evaluation order"? – Aaron Dec 16 '17 at 04:34
  • @Aaron Thanks, I couldn't come up with a better term so I just googled the opposite of simultaneous, I'll change it now – Nick is tired Dec 16 '17 at 04:37

1 Answers1

3

The right side of the = is always evaluated first, in this case it is packing a tuple. That tuple is then unpacked when interpreting the left hand side. The left and right sides do not share knowledge of variables. The RHS becomes a value and then the LHS uses that value to assign to the variables (labels).

In your example the values of x and y are determined after the RHS is evaluated. The unpacking then occurs left to right, so that board[x][y] has valid indices.

Switching the order demonstrates the unpacking sequence:

>>> board[x][y], x, y = move[2], move[0], move[1]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-7-a984ef3168f8> in <module>()
----> 1 board[x][y], x, y = move[2], move[0], move[1]    
NameError: name 'x' is not defined
Nick is tired
  • 6,860
  • 20
  • 39
  • 51
ShpielMeister
  • 1,417
  • 10
  • 23
  • 1
    While I find it unlikely to change, is this stated anywhere to be intended behavior, or is it simply an implementation detail? I can see potential future situations where automated parallelization may break this (again, unlikely but possible). – Aaron Dec 16 '17 at 04:32
  • 3
    https://docs.python.org/3.6/reference/simple_stmts.html?highlight=unpacking%20tuples "Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are ‘simultaneous’ (for example a, b = b, a swaps two variables), overlaps within the collection of assigned-to variables occur left-to-right, sometimes resulting in confusion. For instance, the following program prints [0, 2]: x = [0, 1] i = 0 i, x[i] = 1, 2 # i is updated, then x[i] is updated print(x) – ShpielMeister Dec 16 '17 at 04:41