Page 1 of 1

continuing loop until input (python)

Posted: Thu Jan 24, 2013 8:21 pm UTC
by >-)
how could i make it so that a loop would keep on running until i inputted something. for example, a script that will print out consecutively increasing numbers until i input anything at all. if i put input() in the loop, it'll stop and wait for me to input something, but it also stops counting, so that doesn't work.

something like

Code: Select all

while 1:
    print x
    if input() == 1:
        break

wouldn't work because x wouldn't print continuously -- it'd stop and wait for the input.

Re: continuing loop until input (python)

Posted: Thu Jan 24, 2013 8:44 pm UTC
by The Great Hippo
>-) wrote:how could i make it so that a loop would keep on running until i inputted something. for example, a script that will print out consecutively increasing numbers until i input anything at all. if i put input() in the loop, it'll stop and wait for me to input something, but it also stops counting, so that doesn't work.

something like

Code: Select all

while 1:
    print x
    if input() == 1:
        break

wouldn't work because x wouldn't print continuously -- it'd stop and wait for the input.
The problem, I suspect, is that Python doesn't let you just 'snag' key-presses; it only interprets the things you put into it (and key presses aren't actually 'put' into Python! It has to go fetch them from elsewhere). To do what you want to do, I believe you'd need a UI library (like tkinter) which you would run in the background to 'catch' the key-press. You could also use pygame, which is pretty simple (and largely used for games!).

Alternatively, I think there's something called 'getch()' under the msvcrt library (which is packaged with Python) which should let you 'catch' key presses, but only when you're dealing with Windows (so your program would only function in a windows environment).

But I think your best bet is to find a UI library that supports key-presses and to go with that.

(If you want, I can show you how to easily do this under pygame--however, although I'm not very familiar with tkinter, it might be your best bet--because it's a pretty standard UI for Python!)

Re: continuing loop until input (python)

Posted: Thu Jan 24, 2013 9:29 pm UTC
by >-)
msvcrt.getch() doesn't seem to work or maybe i'm doing it wrong

Code: Select all

while 1:
    print 2
    print msvcrt.getch()


it will only print 2 once, then wait for me to input a key before it continues. i want it to keep printing 2 as fast as it can until i press a key at which point it will print that key and then go back to printing 2's.

i'll try the pygame solution.

Re: continuing loop until input (python)

Posted: Thu Jan 24, 2013 9:46 pm UTC
by The Great Hippo
Well, here's a really simple version of the pygame solution:

Code: Select all

import pygame, sys
from pygame.locals import *

pygame.init()
pygame.display.set_mode((100,100))

while True:
   for event in pygame.event.get():
      if event.type == QUIT: sys.exit()
      if event.type == KEYDOWN and event.dict['key'] == 50:
         print 'break'
   pygame.event.pump()

This causes the code to print 'break' whenever you hit the '2' key (but the pygame window has to have focus). I know there's a way to do this without requiring the pygame window to have focus (or even have a pygame window at all!), but I can't recall how to do it off the top of my head (I think you need to look at pygame Event structure--there's stuff for programs built in pygame that don't have a display window, I think).

Just as a quick and dirty summary: pygame.event.get() gets all the user events; then you check to see their type (the pygame.locals import is where the different types are stored). The 'QUIT' one is just so the program quits cleanly when you close the display window--otherwise, it just looks to see if a KEYDOWN event with a key of '50' (which is the equivalent of '2'--if you want to find out which numbers correspond to which keys, just take out the event.dict['key'] part and switch 'print 'break'' with 'print str(event.dict['key'])' and start finding out).

A much easier way of doing this springs to mind, though: Pygame has a Key module for callbacks (rather than using an Event system). The problem there though is that I am pretty sure it is just about impossible to use this module without a pygame display (so you're stuck with a pygame window).

EDIT: Actually, pardon--at a second glance, the Key module doesn't require the display at all. But as I glance through it, I suspect it wouldn't be useful--if you go with pygame, doing this through the Event system is probably going to be your best bet.

Re: continuing loop until input (python)

Posted: Thu Jan 24, 2013 10:28 pm UTC
by Falling
Alternatively you can try curses.

That has a getch method function (rubyist here), that you can use. Of course then you'll need to introduce a few threads... good learning opportunity!

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 12:14 am UTC
by zmic
This code will print "Hi Mom!" until you press enter (Python 2.7, not Python 3)

Code: Select all

import thread, time

def input_thread(L):
    raw_input()
    L.append(None)
   
def do_print():
    L = []
    thread.start_new_thread(input_thread, (L,))
    while 1:
        time.sleep(.1)
        if L: break
        print "Hi Mom!"
       
do_print()


Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 12:31 am UTC
by The Great Hippo
Oo.

I really need to learn about threads.

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 12:41 am UTC
by EvanED
Falling wrote:Alternatively you can try curses.

That has a getch method function (rubyist here), that you can use. Of course then you'll need to introduce a few threads... good learning opportunity!

I doubt curses's getch will help. I'd wager that does the same thing the msvcrt version does, which waits until a button is pressed. (The difference with the usual IO is that it won't wait until the entire *line* is submitted.)

The threads solution may be the easiest, but you could probably do it if you're on Linux by (1) setting the terminal to raw mode, (2) using the fcntl module to set the file descriptor associated with standard input to non-blocking mode, and (3) calling sys.stdin.read(). If it returns something instead of throw an IOException with errno EAGAIN or EWOULDBLOCK, then the user has pressed a key.

Edit: I actually decided to look, and the curses module supports a non-blocking mode; they call it no-delay mode. Search for nodelay(). So you could use curses as well if you're on Linux.

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 1:01 am UTC
by >-)
i like that solution

Spoiler:
zmic wrote:This code will print "Hi Mom!" until you press enter (Python 2.7, not Python 3)

Code: Select all

import thread, time

def input_thread(L):
    raw_input()
    L.append(None)
   
def do_print():
    L = []
    thread.start_new_thread(input_thread, (L,))
    while 1:
        time.sleep(.1)
        if L: break
        print "Hi Mom!"
       
do_print()



but how do i get it stop when you print out something that has been typed?
i tried to modify your code so it read

Code: Select all

import thread, time


def input_thread(L):
    derp = raw_input()
    L.append(derp)
   
def do_print():
    L = []
    thread.start_new_thread(input_thread, (L,))
    while 1:
        print 'hi mom'
        time.sleep(.1)
        if L:
            print L[0]
            del L[0]
            break
do_print()


and now the break seems to close out the window entirely.

-and i'm on windows

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 2:13 am UTC
by Zabaron
When the program is done, it terminates. If you ran it by just double-clicking on the .py file then the console no longer has a process associated with it and it closes. If you want the console to stay open, you'll need to either run the file from a command prompt (so that when it terminates, the console still has cmd.exe running in it, and will stay open), or have the program wait for some sort of input after the loop breaks (insert a raw_input() after the loop) so that the python script doesn't terminate.

--Zabaron

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 7:14 am UTC
by PM 2Ring
That thread-based solution is rather neat, and more compact than the multi-platform code in this thread.

Re: continuing loop until input (python)

Posted: Fri Jan 25, 2013 12:15 pm UTC
by Derek
Recalling back to my QBasic days, when I did things like this, there was a function that you could call that would ask you if a character was ready (it basically checked if the keyboard buffer was not empty). If true, you could then getch, otherwise just keep looping. This way you could get input without blocking. I'm sure similar functions exist somewhere in python or python libraries.

EDIT: In fact, looking at the curses library, it looks like there is a nodelay function that makes getch non-blocking, and getch will return -1 if no character was available. Try something like (I haven't tested this):

Code: Select all

import curses

window = curses.initscr()
window.nodelay(1)

while True:
    print("Hello, world!")
    ch = window.getch()
    if ch >= 0:
        break
print(ch)


Apparently the msvrct is kbhit(), which returns true if a character is ready, and then you can call getch().

Also, the QBasic function I was remembering was inkey$, and it returned an empty string if there was no character ready, or it returned the next character in the keyboard buffer. Basically the same as getch with no delay.

Re: continuing loop until input (python)

Posted: Sat Jan 26, 2013 3:36 am UTC
by >-)
unfortunately, curses doesn't work on windows. i think i'll use zabaron's solution. thanks everyone.

Re: continuing loop until input (python)

Posted: Sat Jan 26, 2013 5:08 pm UTC
by Derek
Is there really no cross platform version of curses? Even if it was just a wrapper around similar libraries for each platform, it would be very useful.

Re: continuing loop until input (python)

Posted: Sun Jan 27, 2013 7:02 pm UTC
by ahammel
For Windows curses, there's wcurses and console. Nothing cross-platform, so far as I can tell. You might be able to to do this trick:

Code: Select all

try:
    import curses
except ImportError:
    import wcurses as curses
But I'm not sure if wcurses works as a drop-in replacement for curses.

Re: continuing loop until input (python)

Posted: Wed Nov 13, 2013 12:00 am UTC
by sje46
Derek wrote:Recalling back to my QBasic days, when I did things like this, there was a function that you could call that would ask you if a character was ready (it basically checked if the keyboard buffer was not empty). If true, you could then getch, otherwise just keep looping. This way you could get input without blocking. I'm sure similar functions exist somewhere in python or python libraries.

EDIT: In fact, looking at the curses library, it looks like there is a nodelay function that makes getch non-blocking, and getch will return -1 if no character was available. Try something like (I haven't tested this):

Code: Select all

import curses

window = curses.initscr()
window.nodelay(1)

while True:
    print("Hello, world!")
    ch = window.getch()
    if ch >= 0:
        break
print(ch)


Apparently the msvrct is kbhit(), which returns true if a character is ready, and then you can call getch().

Also, the QBasic function I was remembering was inkey$, and it returned an empty string if there was no character ready, or it returned the next character in the keyboard buffer. Basically the same as getch with no delay.


I've been messing with python curses, and I'd say a better solution would be

Code: Select all

import curses

window = curses.initscr()
window.nodelay(1)
ch = -1
while ch < 0:
    # put code continuously run here
    ch = window.getch()
print(ch)


When you press any button the ch will become whatever value that key is, which isn't going to be less than 0.

Re: continuing loop until input (python)

Posted: Wed Nov 13, 2013 2:05 am UTC
by skeptical scientist
One simple, hacky way to do this (but which may be sufficient depending on what you want this for) is to take advantage of a particular input that the python interpreter is always watching for:

Code: Select all

try:
  while 1:
    # do loop stuff
except KeyboardInterrupt:
  # do post-loop stuff

But yeah, the threading way is much nicer.

Re: continuing loop until input (python)

Posted: Wed Dec 18, 2013 12:50 am UTC
by madaco
zmic wrote:This code will print "Hi Mom!" until you press enter (Python 2.7, not Python 3)

Code: Select all

import thread, time

def input_thread(L):
    raw_input()
    L.append(None)
   
def do_print():
    L = []
    thread.start_new_thread(input_thread, (L,))
    while 1:
        time.sleep(.1)
        if L: break
        print "Hi Mom!"
       
do_print()



I tried that on a windows laptop and it isn't working for me.
Specifically, it waits for user input, and then it outputs once.
I believe that it is running the things sequentially.

I tried the multiprocess library trivial example on the python docs as well, and it also didn't work. (it doesn't seem to have called the function at all.)

I'm not sure what I'm doing wrong yet.

Re: continuing loop until input (python)

Posted: Fri Dec 27, 2013 12:24 pm UTC
by >-)
It (referring to some of the multiprocessing examples), doesn't work from the interpreter if you're testing from that. post your code.

Re: continuing loop until input (python)

Posted: Sat Jan 11, 2014 11:05 pm UTC
by madaco
By the interpreter do you mean from the python shell?
Or does it only work when compiled?

I thought the webpage meant the python shell, but the latter would explain my problem.

I'm using:

Code: Select all

from multiprocessing import Process

def f(name):
    print 'hello', name

def fd():
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
fd()

and then pressing f5.

Also, I realized that its not actually finishing the program without doing anything. It seems to actually be hanging. (and not responding for a while when I try to close it)

Is there anything I can do that will work in the interpreter?
(other than catching ctrl-c )

edit:
I also just realized that this caused more than 100 python processes to open. I don't know why.
They also somehow persisted after a forced power off? (???)
(or maybe I ran it again after turning it on)

(either way, I don't recommend running it with the python shell,
though of course because you know much more than me about this, you might be aware of an exception to this advice that I am not aware of)

Re: continuing loop until input (python)

Posted: Sun Jan 12, 2014 10:51 pm UTC
by sonicspin
The Great Hippo wrote:Alternatively, I think there's something called 'getch()' under the msvcrt library (which is packaged with Python) which should let you 'catch' key presses, but only when you're dealing with Windows (so your program would only function in a windows environment).

also, if it hasn't been said, Getch works only with keys with ASCII symbols, the other ones have to be getch'd twice to work
(it's a weird thing involvin 4-digit hex codes and getch only grabbing 2 of those at once (or something) I'm not really a coder much than a person who can do basic stuff)

Re: continuing loop until input (python)

Posted: Thu Jan 16, 2014 12:32 am UTC
by Zabaron
madaco wrote:I also just realized that this caused more than 100 python processes to open. I don't know why.

That's because the child processes have to import f from your module, which runs fd(), which spawns a new child process, which imports your module, which spawns a new child, etc. You need to wrap your fd() call in if __name__ == '__main__', so that it doesn't get called when your module is imported by another.

--Zabaron