Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is sequence unpacking atomic?

Is sequence unpacking atomic? e.g.:

(a, b) = (c, d)

I'm under the impression it is not.

Edit: I meant atomicity in the context of multi-threading, i.e. whether the entire statement is indivisible, as atoms used to be.

like image 495
Tim Diels Avatar asked Nov 30 '12 17:11

Tim Diels


People also ask

What is sequence unpacking?

Sequence unpacking in python allows you to take objects in a collection and store them in variables for later use. This is particularly useful when a function or method returns a sequence of objects.

What is unpacking in Python?

Introduction. Unpacking in Python refers to an operation that consists of assigning an iterable of values to a tuple (or list ) of variables in a single assignment statement. As a complement, the term packing can be used when we collect several values in a single variable using the iterable unpacking operator, * .


2 Answers

It is one operation; the right-hand expression is evaluated before the left-hand assignment is applied:

>>> a, b = 10, 20
>>> a, b
(10, 20)
>>> b, a = a, b
>>> a, b
(20, 10)
>>> a, b = a*b, a/b
>>> a, b
(200, 2)

Or, if you are talking about multi-threaded environments, then the assignment is not atomic; the interpreter evaluates a tuple assignment with a single opcode, but uses separate opcodes to then store the results into each affected variable:

>>> def t(self): a,b=20,20
... 
>>> dis.dis(t)
  1           0 LOAD_CONST               2 ((20, 20))
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               1 (a)
              9 STORE_FAST               2 (b)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE        

However, normal assigment is always going to be at least two opcodes (one for the right-hand expression, one for storing the result), so in python in general assigment is not atomic. Sequence unpacking is no different.

like image 133
Martijn Pieters Avatar answered Oct 05 '22 06:10

Martijn Pieters


Definitely not atomic in a multi-threaded environment, tested using the following script:

import threading

a, b = 10, 10
finished = False
def thr():
    global finished
    while True:
        # if sequence unpacking and assignment is atomic then (a, b) will always
        # be either (10, 10) or (20, 20).  Could also just check for a != b
        if (a, b) in [(10, 20), (20, 10)]:
            print('Not atomic')
            finished = True
            break

t = threading.Thread(target=thr)
t.start()

while True:
    for i in range(1000000):
        a, b = 20, 20
        a, b = 10, 10
    if finished:
        t.join()
        break

Tested using CPython 2.6, 2.7, and 3.2. On each version this script printed 'Not atomic' and exited in well under a second.

like image 24
Andrew Clark Avatar answered Oct 05 '22 05:10

Andrew Clark