Handling keyboard interrupt and wondering if all my variables are updated together

Question:

So I am wondering how exactly the keyboard interrupt relates to variable assignments. I want to know specifically if in the following 2 examples there would be a difference. The difference I am expecting is that in the second case all variables will either be updated with new values or none of them will where as in the first instance some of them may be while others may not before a given interrupt. I’m not sure of this however and that is why I am asking.

while True:
    try:
        a = foo()
        b = bar()
        c = baz()
    except KeyboardInterrupt:
        print (a,b,c)

#vs.

def bam(a,b,c):
    return foo(),bar(),baz()
    
while True:
    try:
        a,b,c = bam(a,b,c)
    except KeyboardInterrupt:
        print (a,b,c)

I ran the following to check things out.

a,b,c = 0,0,0
def increment(n):
    return n+1

while True:
    try:
        a = increment(a)
        b = increment(b)
        c = increment(c)
    except KeyboardInterrupt:
        if a!=b or a!=c:
            print (a,b,c)
            break

#vs.

def bam(a,b,c):
    return increment(a),increment(b),increment(c)
    
while True:
    try:
        a,b,c = bam(a,b,c)
    except KeyboardInterrupt:
        if a!=b or a!=c:
            print (a,b,c)
            break

It demonstrates that multiple assignment is indeed as @MichaelRuth says "non-atomic".

Asked By: kpie

||

Answers:

This is really the question: "Are multiple assignment statements atomic?" Let’s take a look at the disassembled code to see. I’ll limit the code to disassemble to just the assignments for clarity.

import dis
dis.dis('a=1;b=2;c=3')
dis.dis('a,b,c = 1,2,3')
  1           0 LOAD_CONST               0 (1)
              2 STORE_NAME               0 (a)
              4 LOAD_CONST               1 (2)
              6 STORE_NAME               1 (b)
              8 LOAD_CONST               2 (3)
             10 STORE_NAME               2 (c)
             12 LOAD_CONST               3 (None)
             14 RETURN_VALUE
  1           0 LOAD_CONST               0 ((1, 2, 3))
              2 UNPACK_SEQUENCE          3
              4 STORE_NAME               0 (a)
              6 STORE_NAME               1 (b)
              8 STORE_NAME               2 (c)
             10 LOAD_CONST               1 (None)
             12 RETURN_VALUE

Multiple assignment is not atomic; however, there is only one LOAD_CONST operation so there is less probability that the interrupt will occur during assignment and result in a partial assignment. Said another way: there are four ops remaining in the assignments after a is assigned in the version with single assignment statements, but there are only two ops remaining in the assignments after a is assigned in the version with multiple assignment.

Please note that this disassembly was produced using CPython 3.10 on a Mac. It could be different on other platforms and other Python implementations.

Answered By: Michael Ruth

For latter code block:
If you read through this. It has mentions that in case of expressions first the right hand side of the equals to (=) symbol is evaluated and then it is assigned to left hand side.
If there is a function on right, first of all it will execute the block of code present in that function, here it will execute bam(a,b,c) which will execute foo(),bar(),baz() and then call the return statement.
If KeyboardInterrupt happens before a,b,c are assigned values. It will throw an error because we are trying to access variable that are not yet defined properly.

The first code block would be the same as you expected, it will execute one line at a time, and would error out for the variables that are not defined properly.

So overall you were right in predicting the outputs.

Answered By: Mr. Techie
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.