序列解包是原子的吗?

tim*_*els 5 python atomic variable-assignment

序列解包是原子的吗?例如:

(a, b) = (c, d)
Run Code Online (Sandbox Code Playgroud)

我的印象不是.

编辑:我的意思是在多线程的上下文中的原子性,即整个语句是否是不可分割的,就像原子一样.

Mar*_*ers 6

这是一个操作; 在应用左侧赋值之前评估右侧表达式:

>>> 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)
Run Code Online (Sandbox Code Playgroud)

或者,如果您正在谈论多线程环境,那么赋值不是原子的; 解释器使用单个操作码评估元组赋值,但使用单独的操作码将结果存储到每个受影响的变量中:

>>> 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        
Run Code Online (Sandbox Code Playgroud)

但是,正常的分配总是至少有两个操作码(一个用于右侧表达式,一个用于存储结果),因此在python 中一般来说,分配不是原子的.序列拆包也不例外.


And*_*ark 5

在多线程环境中绝对不是原子的,使用以下脚本进行测试:

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
Run Code Online (Sandbox Code Playgroud)

使用 CPython 2.6、2.7 和 3.2 进行测试。在每个版本中,该脚本都打印出“Not atomic”并在一秒钟内退出。