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.
Imagine I had this:
#file main.py
while alive:
msg = input()
print(msg)
Now in another thread I evaluate either if 'alive' is True or False.
The problem is input() will keep the program hanging.
Is there a way to force it to move on without user interacting with the program?
Or can I just terminate the whole program from inside the other thread?
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")
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)
I have a problem in managing a infinite while loop in Python, in which I would insert a timer as a sort of "watchdog". I try to explain better: the script has to listen on a serial channel and wait for messages coming from sensors connected on the other side of the channel.
I do this with a while True loop because the script must catch all the signals that are passing. However, even if it's probably unnecessary, i would like to insert a timer which is always reset every loop. So, if (for example) the loop get stuck for some reason, the timer will end and will exit the program. I thought i could do this in this way:
def periodicUpdate():
exitTimer = threading.Timer(60.0, sys.exit())
while True:
exitTimer.start()
readData()
exitTimer.cancel()
Now, the problem is that when i start the script it immediatly exit. It seems that it reads sys.exit() before all the rest, and it doesn't respect the construct of the timer, but simply when periodicUpdate is called it exits. Why this happen?! I tried changing the syntax, putting sys.exit in an other function and call that function, i tried other solutions but always it behave in two ways: it exits or it behave as the timer doesn't exists. Can someone help me? Thanks very much
Remove the parentheses. If you use sys.exit(), it will fire straight away. When you use sys.exit, it will pass the function as Timer's second argument.
I think your approach is not the best one, instead of running a timer that exits the application, why not simply timeout the function that reads the data:
Timeout on a function call
It seems that it reads sys.exit() before all the rest
Sure it does. The second argument of threadint.Timer is a function that will be called. What you do is you actually call sys.exit and supply its return value (which is undefined, by the way, since the call terminates the program) as a function to be called. That's an error, since sys.exit's return value is not a function, but that doesn't matter, as the program is terminated anyway.
What you want to do is
exitTimer = threading.Timer(60.0, sys.exit) # note: no brackets
But that actually will not work, as sys.exit in the thread will terminate only that thread. In short, you can't use a watchdog to terminate a stuck while-loop if this loops is in your main thread. In your particular situation you should investigate the function you are using to read data, most likely it lets you set a read timeout.
It seems to me that none of the solutions proposed here actually works. This is an example of code. Would be great to know how to fix it. Also, please try it before answering.
import time, threading, sys
def _exit():
print 'exiting'
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(2.0, _exit)
while True:
exitTimer.start()
print 'go'
time.sleep(5)
exitTimer.cancel()
periodicUpdate()
The actual output is:
$python test.py
go
exiting
RuntimeError: threads can only be started once
exitTimer = threading.Timer(60.0, sys.exit)
Remove the () from sys.exit in timer call
def _exit()
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(60.0, _exit)
while True:
exitTimer.start()
readData()
exitTimer.cancel()
In you put the () the interpreter call this function if not the interpreter get a reference for this function.
Have fun :)
Edit: Use of _exit
threading.Timer(60.0, os._exit, [0])
def periodicUpdate():
exitTimer = sys.exit(60.0, sys.exit())
while sys.exit():
sys.exit()
readData()
sys.exit()
if __name__ == "__main__":
sys.exit()
Don't forget to import sys.