How to exit a while loop only after the current loop has completed in Python?

Question:

I’m trying to set up my Python script to allow the user to end the program, however the program needs to finish what it’s doing first. I have the following code set up:

import sys
import keyboard
import time

prepareToStop = 0;
try:
    while prepareToStop == 0:
        #Program code here
        print(prepareToStop)
        time.sleep(0.1)
except KeyboardInterrupt:
    prepareToStop = 1
    print("nProgram will shut down after current operation is complete.n")

print("Program shutting down...")
sys.exit()

However, the program still exits the loop as soon as the KeyboardInterrupt is received. I’ve seen advice that this could be fixed by placing the ‘try, except’ inside the while loop, however this causes the program to fail to detect the KeyboardInterrupt at all.

Asked By: Straxan

||

Answers:

If I understand your problem correctly, maybe threading can help you. Note how end do something appears even after KeyboardInterrupt.

EDIT : I placed t.join() in the try

import sys
import time
import threading

def do_something(prepareToStop):
    print(prepareToStop)
    time.sleep(1)
    print('end do something')

prepareToStop = 0
while prepareToStop == 0:
    t = threading.Thread(target=do_something, args=[prepareToStop])
    try:
        t.start()
        t.join() # wait for the threading task to end
    except KeyboardInterrupt:
        prepareToStop = 1
        print("nProgram will shut down after current operation is complete.n")
    print('will not appear for last run')

print("Program shutting down...")
sys.exit()

Example of output :

0
end do something
will not appear for last run
0
^C
Program will shut down after current operation is complete.

will not appear for last run
Program shutting down...

end do something
Answered By: Phoenixo

The keyboard interrupt that you were trying to use works like any system interrupt and will jump immediately to the exception block, without going back to where it was when the interrupt has occurred.
You can confirm this by using the debugger in your IDE (ie. Press F5 in VSCODE).

The code below works like you want, but the user has to hold ESC key pressed in the keyboard for it to be captured from the program in the proper time.

import sys
import keyboard
import time

prepareToStop = 0;

while prepareToStop == 0:
    if keyboard.is_pressed('Esc'):
        prepareToStop = 1
        print("nProgram will shut down after current operation is complete.n")
    #Program code here
    print('Sleeping 5 sec - hold the ESC key for some time to exit')
    time.sleep(5)
    print('This prints only after the delay')
    #end code here
    print(prepareToStop)
    time.sleep(0.1)
        
print("Program shutting down...")
sys.exit()

And then I would recommend to change into this:

import sys
import keyboard
import time


while not keyboard.is_pressed('Esc'):
    #Program code here
    print('Sleeping 5 sec - hold the ESC key for some time to exit')
    time.sleep(5)
    print('This prints only after the delay')
    #end code here
    time.sleep(0.1)
        
print("Program shutting down...")
sys.exit()

The above solution is not better than using threading, but it is much more simpler.

Answered By: Marcus Vdt
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.