Mal sehen:
>>> x = 1
>>> y = 2
>>> def swap_xy():
... global x, y
... (x, y) = (y, x)
...
>>> dis.dis(swap_xy)
3 0 LOAD_GLOBAL 0 (y)
3 LOAD_GLOBAL 1 (x)
6 ROT_TWO
7 STORE_GLOBAL 1 (x)
10 STORE_GLOBAL 0 (y)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
Es scheint nicht, dass sie atomar: die Werte von x und y könnte von einem anderen Thread zwischen geändert werden die LOAD_GLOBAL
Bytecodes, vor oder nach dem ROT_TWO
und zwischen den STORE_GLOBAL
Bytecodes.
Wenn Sie zwei Variablen atomar vertauschen möchten, benötigen Sie eine Sperre oder einen Mutex.
Für all jene, empirischen Beweis:
>>> def swap_xy_repeatedly():
... while 1:
... swap_xy()
... if x == y:
... # If all swaps are atomic, there will never be a time when x == y.
... # (of course, this depends on "if x == y" being atomic, which it isn't;
... # but if "if x == y" isn't atomic, what hope have we for the more complex
... # "x, y = y, x"?)
... print 'non-atomic swap detected'
... break
...
>>> t1 = threading.Thread(target=swap_xy_repeatedly)
>>> t2 = threading.Thread(target=swap_xy_repeatedly)
>>> t1.start()
>>> t2.start()
>>> non-atomic swap detected
Warum? GIL? Die Disassemblierung deutet nicht auf Atomizität hin (siehe @ jemfinchs Antwort). – kennytm
(Übrigens, der obige Kommentar ist * nicht * eine rhetorische Frage.) – kennytm
@Kenny: Es war ein Missverständnis meiner Rolle, wie das Tupel-Entpacken auf niedrigem Niveau funktioniert hat. – voyager