non è atomica, perché ci vuole più istruzioni bytecode da assegnare a più nomi e non ci vuole molto per confermare sperimentalmente:
import signal
a = 1
b = 2
def handler(sig, trace):
print a, b
def main():
global a, b
signal.signal(signal.SIGINT, handler)
while True:
a, b = 3, 4
a, b = 1, 2
if __name__ == '__main__':
main()
$ python atom.py
^C3 4
^C3 4
^C1 2
^C1 2
^C3 4
^C1 2
^C1 2
^C1 2
^C1 2
^C1 4 <<<< inconsistent state
In questo caso particolare, se si vuole due valori cambiare dal punto di vista atomico, è possibile cavarsela assegnando la tupla e accedendo ai suoi elementi nel gestore del segnale. Guardando lo smontaggio:
>>> a = 1
>>> b = 2
>>> c = (1, 2)
>>> def foo():
... global a, b
... a, b = 1, 2
...
>>> def bar():
... global c
... c = (1, 2)
...
>>> dis.dis(foo)
3 0 LOAD_CONST 3 ((1, 2))
3 UNPACK_SEQUENCE 2
6 STORE_GLOBAL 0 (a)
9 STORE_GLOBAL 1 (b)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
>>> dis.dis(bar)
3 0 LOAD_CONST 3 ((1, 2))
3 STORE_GLOBAL 0 (c)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
Non importa quanto sia complesso il valore è, l'assegnazione a una variabile (o dict
ingresso, o un campo oggetto) è una singola operazione di memorizzazione atomica.
Vedi anche: http://stackoverflow.com/questions/2623086/is-a-variable-swap-guaranteed-to-be-atomic-in-python – nemo