Python - Infinite while loop, break on user input
Asked Answered
S

7

12

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?

Shalloon answered 13/12, 2013 at 22:16 Comment(7)
This thread might be helpful (contains a working example with curses): ubuntuforums.org/showthread.php?t=1514035Engulf
Listening to an event?Quotidian
There are Windows specific ways to do this in the msvcrt module.Biddle
@alKid, Not exactly. I am logging data for something that is manually started and ended by the user. It's something that can't be controlled, currently, from my script.Shalloon
The thread also links to a recipe that might be applicable: code.activestate.com/recipes/…Engulf
You must support windows?Overstay
Possible duplicate of Asking the user for input until they give a valid responseKayne
M
8

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.

Mosesmosey answered 13/12, 2013 at 22:49 Comment(0)
K
14

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)
Kelleekelleher answered 13/12, 2013 at 22:43 Comment(1)
It should be noted that your answer is Unix specific. I'm personally on Windows, but this code is still good to have.Shalloon
M
8

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.

Mosesmosey answered 13/12, 2013 at 22:49 Comment(0)
D
6

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()
Darell answered 28/11, 2017 at 20:43 Comment(0)
T
3

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.

Titivate answered 2/2, 2019 at 5:47 Comment(0)
S
2

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
Shalloon answered 13/12, 2013 at 22:32 Comment(0)
P
2

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

Polestar answered 13/12, 2013 at 22:44 Comment(0)
V
0

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()
Victualage answered 26/1, 2021 at 14:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.