How to break out of a loop nicely? - python

I have a program that does some work in a timed while loop like so:
import time
While True:
do something
time.sleep(60)
I would like to be able to break out of the loop nicely from the console and save some data on the way out. The solution I have thought of is to create a file when I want the program to quit and check for the file inside the loop like so.
from os.path import exists
While True:
do something
if exists('exit.txt'):
print('exiting')
clean_up()
time.sleep(60)
Is there a better way?

Put them into try catch statement. When you want to end the loop, exit the cycle through Ctrl+C, and then complete the work you want to finish:
>>> try:
... while True: pass
... except KeyboardInterrupt:
... print('hello')
...
[^C]
hello

Use the break keyword to exit a loop when a condition is met:
from os.path import exists
while True:
do_something()
if exists('exit.txt'):
print('exiting')
break
time.sleep(60)
clean_up()
As Mechanic Pig mentioned in his answer, if you want to be able to manually break out of it from the console, you could implement a KeyboardInterrupt handler:
while True:
try:
do_something()
if exists('exit.txt'):
print('exiting')
break
else:
time.sleep(60)
continue
except KeyboardInterrupt:
print('exiting')
break
clean_up()

Related

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

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.
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
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.

Python: A robust continuous loop with keyword keyboard interrupt

Currently I have a program which follows:
try:
while True:
print("Running")
except KeyboardInterrupt:
pass
The idea bring that the terminal will print "Running" until the user inputs CRTL+C, what I want to be able to do is have the program continue to run until a user enters a key word in additional to this. This is to make my program more robust so no accidental inputs could stop the loop.
Is there a way to do this?
Here a possible way to achieve that:
while True:
try:
print("Running")
except KeyboardInterrupt:
if input("Type exit to exit: ") != "exit":
continue
break
Or if you want to a more flexible escaping string you can declare it as follow:
escape_string = "exit"
while True:
try:
print("Running")
except KeyboardInterrupt:
if input(f"Type {escape_string} to exit: ") != escape_string:
continue
break
You need the try/except block to be inside the loop, so that the interrupt does not exit the loop. The exception handler activates the loop exit condition.
ans = ""
while ans != "please":
try:
print("Running")
sleep(1)
except KeyboardInterrupt:
ans = input("Please enter secret ")

Python- How to check if program gets aborted by user while running?

If I am running a python program on linux terminal and i abort it manually by pressing ctrl+c, how can i make my program do something when this event occurs.
something like:
if sys.exit():
print "you chose to end the program"
You can write a signal handling function
import signal,sys
def signal_handling(signum,frame):
print "you chose to end the program"
sys.exit()
signal.signal(signal.SIGINT,signal_handling)
while True:
pass
pressing Ctrl+c sends a SIGINT interrupt which would output:
you chose to end the program
Well, you can use KeyBoardInterrupt, using a try-except block:
try:
# some code here
except KeyboardInterrupt:
print "You exited
Try the following in your command line:
import time
try:
while True:
time.sleep(1)
print "Hello"
except KeyboardInterrupt:
print "No more Hellos"
Check the KeyboardInterrupt exception in Python.
You can put your code in a try block, catch the KeyboardInterrupt exception with except and let the user know that he has exited.

When cancelling a Python script do something [duplicate]

This question already has answers here:
How do I capture SIGINT in Python?
(12 answers)
Closed 9 years ago.
When i press CTRL+C to cancel a running python script, is there a way to run a certain python code before the script terminates?
Use try/except to capture for KeyboardInterrupt, which is raised when you press CTRL+C.
Here is a basic script to demonstrate:
try:
# Main code
while True:
print 'hi!'
except KeyboardInterrupt:
# Cleanup/exiting code
print 'done!'
This will continually print 'hi!' until you press CTRL+C. Then, it prints 'done!' and exits.
CTRL+C raises KeyboardInterrupt. You can catch it just like any other exception:
try:
main()
except KeyboardInterrupt:
cleanup()
If you really don't like that, you can also use atexit.register to register cleanup actions to run (provided that you don't do something really nasty and cause the interpreter to exit in a funky way)
try:
# something
except KeyboardInterrupt:
# your code after ctrl+c
I'm pretty sure you just need a try/finally block.
Try out this script:
import time
def main():
try:
while True:
print("blah blah")
time.sleep(5)
except KeyboardInterrupt:
print("caught CTRL-C")
finally:
print("do cleanup")
if __name__ == '__main__':
main()
Output should be something like:
blah blah
caught CTRL-C
do cleanup
This code
import time
try:
while True:
time.sleep(2)
except KeyboardInterrupt:
print "Any clean"
gives
deck#crunch ~/tmp $ python test.py
^CAny clean
when I press Ctrl+C when executing.
You just have to handle KeyboardInterrupt exception.
Also you can deal with signals to set handlers.

Python - Infinite while loop, break on user input

I have an infinite while loop that I want to break out of when the user presses a key. Usually I use raw_input to get the user's response; however, I need raw_input to not wait for the response. I want something like this:
print 'Press enter to continue.'
while True:
# Do stuff
#
# User pressed enter, break out of loop
This should be a simple, but I can't seem to figure it out. I'm leaning towards a solution using threading, but I would rather not have to do that. How can I accomplish this?
You can use non-blocking read from stdin:
import sys
import os
import fcntl
import time
fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, fl | os.O_NONBLOCK)
while True:
print("Waiting for user input")
try:
stdin = sys.stdin.read()
if "\n" in stdin or "\r" in stdin:
break
except IOError:
pass
time.sleep(1)
I think you can do better with msvcrt:
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
if msvcrt.getwche() == '\r':
break
time.sleep(0.1)
print(i)
Sadly, still windows-specific.
On python 3.5 you can use the following code. It can be adjusted for a specific keystroke. The while loop will keep running until the user presses a key.
import time
import threading
# set global variable flag
flag = 1
def normal():
global flag
while flag==1:
print('normal stuff')
time.sleep(2)
if flag==False:
print('The while loop is now closing')
def get_input():
global flag
keystrk=input('Press a key \n')
# thread doesn't continue until key is pressed
print('You pressed: ', keystrk)
flag=False
print('flag is now:', flag)
n=threading.Thread(target=normal)
i=threading.Thread(target=get_input)
n.start()
i.start()
I could not get some of the popular answers working. So I came up with another approach using the CTRL + C to plug in user input and imbibe a keyboard interrupt. A simple solution can be using a try-catch block,
i = 0
try:
while True:
i+=1
print(i)
sleep(1)
except:
pass
# do what you want to do after it...
I got this idea from running a number of servers like flask and django. This might be slightly different from what the OP asked, but it might help someone else who wanted a similar thing.
Using the msvcrt module as thebjorn recommended I was able to come up with something that works. The following is a basic example that will exit the loop if any key is pressed, not just enter.
import msvcrt, time
i = 0
while True:
i = i + 1
if msvcrt.kbhit():
break
time.sleep(0.1)
print i
What you need is a non-blocking raw input, if you don't want to use threads there is a simple solution like this one below where he is doing a timeout of 20 ms and then raise and exception if the user doesn't press a key, if he does then the class returns the key pressed.
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Source code
I have defined the function which ask number input from the user and returns the factorial of that number. If user wants to stop they have to press 0 and then it will exit from the loop. We can specify any specific key to input 'n' to exit from the loop.
import math
def factorial_func(n):
return math.factorial(n)
while True:
n = int(input("Please enter the number to find factorial: "))
print(factorial_func(n))
if n == 0:
exit()

Categories

Resources