Reputation: 479
I am writing a program which executes in some standard fashion, unless the user inputs something in terminal, in which case the program should change the behavior, e.g.
while True:
# do something here
def interrupt(user_input):
if user_input == "some command":
sys.exit(0) # e.g.
How to achieve this by not having input()
in while
loop?
Upvotes: 2
Views: 4103
Reputation: 5237
The simplest interpretation here is to use a daemon thread.
To achieve this in Python, you can make use of multi-threading. For that, there is the threading
module.
Your daemon would run in the background, by setting daemon=True
when creating the thread.
Below is a simple example of that in action. Your main logic would go in the main
function. The while True
infinite loop listens for user input and terminates the program once the user input matches some predefined value ("kill"
in this case).
import sys
import threading
def main():
print('Main program')
while True:
pass
# Rest of main program
main_thread = threading.Thread(name='main program',
target=main, daemon=True)
main_thread.start()
while True:
if input().lower() == 'kill':
print('Terminating program')
# Add some possible cleanup code here
sys.exit(0)
Take note of this important information from the Python documentation about how daemonic threads are stopped:
Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.
That said, this approach may suffice for your purposes. Depending on your program logic, if some cleanup code is needed, it could be done before exiting -- since once the sys.exit(0)
is called, the daemonic thread will be killed abruptly.
A more general solution, however, is to make use of threading.Event
.
This is quite a distinct approach to the above in that we create a regular, non-daemonic thread and pass an Event
to it. This time, instead of abruptly exiting the program on user input, we set
the internal flag of the Event
.
In parallel, instead of a while True
infinite loop, the main
function uses the non-blocking is_set()
to break the loop once the Event
is set.
import threading
def main(e):
print('Main program')
while not e.is_set():
pass
# Rest of main program
print('Exiting')
# Add some possible cleanup code here
e = threading.Event()
main_thread = threading.Thread(name='main program',
target=main, args=(e,))
main_thread.start()
while True:
if input().lower() == 'kill':
print('Terminating program')
e.set()
break
main_thread.join()
This has two advantages over the daemonic approach described:
Event
s and have your program behave in different ways, depending on those events. There is also the blocking Event.wait()
you can use instead of Event.is_set()
.main()
function.Upvotes: 5