I'm a total newbie and I have question about asking about input while the loop is working.
Lets pretend that i have simple loop.
x = 1
y = 1
while x == 1:
y += 1
print(y)
And now i want user input to stop this script but only if he types cancel and the loop is supposed to run while python is waiting for input.
As I mentioned in the comments you can achieve "running the loop while waiting for input" using threads from the threading module.
The idea is to have two threads that will run in parallel (ie at the same time) and each of them will do its own thing. The first one will do only one thing : wait for input. The second one will do the work that you would have put in the loop, and only check at the start of each loop if it should stop or not according to the information it gets from the first thread.
The following code illustrate this (note this requires python3):
from threading import Thread
import time
class Input_thread(Thread):
def __init__(self):
Thread.__init__(self)
self.keep_working = True
def run(self):
while True:
a = input("Type *cancel* and press Enter at anytime to cancel \n")
print("You typed "+a)
if a == "cancel":
self.keep_working = False
return
else:
pass
class Work_thread(Thread):
def __init__(self, other_thread):
Thread.__init__(self)
self.other_thread = other_thread
def run(self):
while True:
if self.other_thread.keep_working is True:
print("I'm working")
time.sleep(2)
else :
print("I'm done")
return
# Creating threads
input_thread = Input_thread()
work_thread = Work_thread(input_thread)
# Lanching threads
input_thread.start()
work_thread.start()
# Waiting for threads to end
input_thread.join()
work_thread.join()
As you can see using threading isn't trivial and requires some knowledge about classes.
A way of achieving something similar in a slightly simpler way would be to use the python's exception called KeyboardInterrupt. If you are not familiar with exceptions : there are python's way of handling errors in your code, that means if at some point in your code Python finds a line it can't run, it will raise an exception, and if nothing was planned to deal with that error (aka if you don't catch the exception with the try/except syntax), python stops running and display that exception and the traceback in the terminal window.
Now the thing is when you press Ctrl-c (same as the copy shortcut) in the terminal window while your program runs, it will automaticaly raise an exception called KeyboardInterupt in your program, and you can catch it to use it as way to send cancel to your program.
See that code for an example of how to do that :
import time
y=1
try:
while True:
y+=1
print(y)
time.sleep(1)
except KeyboardInterrupt:
print("User pressed Ctrl-c, I will now exit gracefully")
print("Done")
Related
I need to break from time.sleep() using ctrl c.
While 1:
time.sleep(60)
In the above code when the control enters time.sleep function an entire 60 seconds needs to elapsed for python to handled the CTRL C
Is there any elegant way to do it. such that I can interrupt even when the control is in time.sleep function
edit
I was testing it on a legacy implementation which uses python 2.2 on windows 2000 which caused all the trouble . If I had used a higher version of python CTRL C would have interrupted the sleep() . I did a quick hack by calling sleep(1) inside a for loop . which temporarily fixed my issue
The correct answer is to use python stdlib's threading.Event
Sure you can tune down your sleep interval so you sleep for very short periods, but what if you actually want to run your loop once every 60s? Then you need to do more work to determine if it's time to run or just keep sleeping. Furthermore, you're still technically blocking but for only a short period of time. Contrast to threading.Event:
from threading import Event
exit = Event()
def main():
while not exit.is_set():
do_my_thing()
exit.wait(60)
print("All done!")
# perform any cleanup here
def quit(signo, _frame):
print("Interrupted by %d, shutting down" % signo)
exit.set()
if __name__ == '__main__':
import signal
for sig in ('TERM', 'HUP', 'INT'):
signal.signal(getattr(signal, 'SIG'+sig), quit);
main()
When the signal handler calls exit.set(), the main thread's wait() call will immediately be interrupted.
Now, you could use an Event to signal that there's more work to do, etc. But in this case it does double duty as a convenient indicator that we want to quit (e.g. the while not exit.is_set() part.)
You also have the option to put any cleanup code after your while loop.
Not sure what the sense of this code is - but if necessary use a shorter sleep() interval and put a for loop around it:
for i in range(60):
sleep(1)
Catching the KeyboardInterrupt exception using try..except is straight-forward
The KeyboardInterrupt exception is raised when a user hits the interrupt key, Ctrl-C. In python this is translated from a SIGINT signal. That means, you can get handle it however you want using the signal module:
import signal
def handler(signum, frame):
print("do whatever, like call thread.interrupt_main()")
signal.signal(signal.SIGINT, handler)
print("Waiting for SIGINT...")
signal.pause()
That way, you can do whatever you want at the receipt of a keyboard interrupt.
The most elegant solution is certainly threading.Event, though if you only need a quick hack, this code works well :
import time
def main():
print("It’s time !")
if __name__ == "__main__":
print("press ctrl-c to stop")
loop_forever = True
while loop_forever:
main()
try:
time.sleep(60)
except KeyboardInterrupt:
loop_forever = False
I tried your code with python versions 2.5, 2.6, 3 under Linux and all throw "KeyboardInterrupt" exception when hitting CTRL-C.
Maybe some exception handling catches the Interrupt or your problem is like this:
Why is KeyboardInterrupt not working in python?
Based on #Andreas Jung answer
for i in range(360):
try:
sleep(1)
except KeyboardInterrupt:
sys.exit(0)
Figured I'd throw this in.
import time
def sleep(seconds):
for i in range(seconds):
try:
time.sleep(1)
except KeyboardInterrupt:
print("Oh! You have sent a Keyboard Interrupt to me.\nBye, Bye")
break
sleep(60)
I have a small script where I have a continuous loop. The loop runs and I expect that the user will give an input whenever he wants. I want to check if the user wrote something in the console, if yes, I will do something extra, if not, the loop continues.
The problem is that when I call the input() function, the program waits for user input.
The code that I will use here will be just a simple version of my code to show better what is my problem.
i=0
while True:
i+=1
if 'user wrote a number':
i+= 'user's input'
The objective is to not stop the loop if the user do not input anything. I believe this is a simple thing but I didn't find an answer for this problem.
Thank you for your time!
You can execute the background task (the while True) on a separate thread, and let the main thread handle the input.
import time
import threading
import sys
def background():
while True:
time.sleep(3)
print('background task')
def handling_input(inp):
print('Got {}'.format(inp))
t = threading.Thread(target=background)
t.daemon = True
t.start()
while True:
inp = input()
handling_input(inp)
if inp == 'q':
print('quitting')
sys.exit()
Sample execution (lines starting with >> are my inputs):
background task
>> a
Got a
>> b
Got b
background task
>> cc
Got cc
background task
background task
>> q
Got q
quitting
Process finished with exit code 0
The only caveat is if the user takes longer than 3 seconds to type (or whatever the value of time.sleep in background is) the input value will be truncated.
I'm don't think you can do that in one single process input(), because Python is a synchronous programming languaje,the execution will be stoped until input() receives a value.
As a final solution I'd recommend you to try implement your functions with parallel processing so that both 'functions' (input and loop) can get executed at the same time, then when the input function gets it's results, it sends the result to the other process (the loop) and finish the execution.
I have a thread that monitors user input which looks like this:
def keyboard_monitor(temp): #temp is sys.stdin
global flag_exit
while True:
keyin = temp.readline().rstrip().lower()
if keyin == "exit":
flag_exit = True
print("Stopping...")
if flag_exit == True:
break
If I type exit the flag is properly set and all the other threads terminate. If another one of my threads sets the flag, this thread refuses to finish because it's hanging on the user input. I have to input something to get it to finish. How do I change this code so that the program finishes when the flag is set externally?
Its hard to tell exactly what is going wrong without more of your code, but as an easy solution you could rather exit() which is a python built in. This should reliably terminate the application, also sys.exit()
From wim's comment:
You can use the atexit module to register clean up handlers
import atexit
def cleanup():
pass
# TODO cleanup
atexit.register(cleanup)
Is it possible to write an infinite loop that exceptions can't break out of even when the exceptions happen between executions of the loop body? If so, how? (These are the sort of silly things I think about when I ponder robustness.)
For example, consider the following code:
import time
def slow_true():
print 'waiting to return True...'
time.sleep(1.0)
return True
while slow_true():
try:
print 'in loop body'
raise RuntimeError('testing')
except:
print 'caught exception, continuing...'
continue
I can easily break out of the loop with Ctrl-C while Python is executing slow_true(). Even if I replace while slow_true(): with while True: there is theoretically a small window of time (between executions of the body) where a SIGINT can cause the script to exit.
I realize I can implement a SIGINT handler to effectively disable Ctrl-C, but that's not the point of this question.
I could wrap the loop with another infinite loop and move the try/except out a level like so:
import time
def slow_true():
print 'waiting to return True...'
time.sleep(1.0)
return True
while True:
try:
while slow_true():
print 'in loop body'
raise RuntimeError('testing')
except:
print 'caught exception, restarting...'
continue
break
This would make it much harder to break out of the loop (two exceptions would have to be raised back-to-back at just the right times), but I think it's still theoretically possible.
One definitely not recommended option is to override the excepthook method.
import sys
def exception_hook(exception_type, value, traceback):
your_loop_function()
sys.excepthook = exception_hook
Alternative solution using signals (less bad):
import signal
def interrupt(signal, frame):
your_loop_function()
signal.signal(signal.SIGINT, interrupt)
I have two programs
program1.py is like commandline interface which takes command from user
program2.py has the program which runs the relevant program as per the command.
Program 1 has also has an quit_program() module
In our simple universe.. lets say I have just one command and just one program
So lets say...
program1.py
def main():
while True:
try:
command = raw_input('> ')
if command == "quit" :
return
if command == '':
continue
except KeyboardInterrupt:
exit()
parseCommand(command)
And then I have:
if commmand == "hi":
say_hi()
Now program2 has
def say_hi():
#do something..
Now there can be two cases...
Either say_hi() completes in which case no issue...
But what i want is that if user enters a command (say: end)
then this say_hi() is terminated in between..
But my current implementation is very sequential.. I mean I dont get to type anything on my terminal untill the execution is completed..
Somethng tells me that the say_hi() should be running on another thread?
I am not able to think straight about this.
Any suggestions?
Thanks
The threading module is what you are looking for.
import threading
t = threading.Thread(target=target_function,name=name,args=(args))
t.daemon = True
t.start()
The .daemon option makes it so you don't have to explicitly kill threads when your app exits... Threads can be quite nasty otherwise
Specific to this question and the question in the comments, the say_hi function can be called in another thread as such:
import threading
if commmand == "hi":
t = threading.Thread(target=say_hi, name='Saying hi') #< Note that I did not actually call the function, but instead sent it as a parameter
t.daemon = True
t.start() #< This actually starts the thread execution in the background
As a side note, you must make sure you are using thread safe functions inside of threads. In the example of saying hi, you would want to use the logging module instead of print()
import logging
logging.info('I am saying hi in a thread-safe manner')
You can read more in the Python Docs.