continuing loop until input (python)

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

>-)
Posts: 527
Joined: Tue Apr 24, 2012 1:10 am UTC

continuing loop until input (python)

Postby >-) » Thu Jan 24, 2013 8:21 pm UTC

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.

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: continuing loop until input (python)

Postby The Great Hippo » Thu Jan 24, 2013 8:44 pm UTC

>-) 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!)

>-)
Posts: 527
Joined: Tue Apr 24, 2012 1:10 am UTC

Re: continuing loop until input (python)

Postby >-) » Thu Jan 24, 2013 9:29 pm UTC

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.

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: continuing loop until input (python)

Postby The Great Hippo » Thu Jan 24, 2013 9:46 pm UTC

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.

Falling
Posts: 175
Joined: Mon Nov 24, 2008 4:30 pm UTC

Re: continuing loop until input (python)

Postby Falling » Thu Jan 24, 2013 10:28 pm UTC

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!

User avatar
zmic
Posts: 427
Joined: Fri Mar 02, 2012 10:38 pm UTC

Re: continuing loop until input (python)

Postby zmic » Fri Jan 25, 2013 12:14 am UTC

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()


User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: continuing loop until input (python)

Postby The Great Hippo » Fri Jan 25, 2013 12:31 am UTC

Oo.

I really need to learn about threads.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: continuing loop until input (python)

Postby EvanED » Fri Jan 25, 2013 12:41 am UTC

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.

>-)
Posts: 527
Joined: Tue Apr 24, 2012 1:10 am UTC

Re: continuing loop until input (python)

Postby >-) » Fri Jan 25, 2013 1:01 am UTC

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

User avatar
Zabaron
Posts: 113
Joined: Wed Jun 04, 2008 3:33 am UTC
Location: Georgia

Re: continuing loop until input (python)

Postby Zabaron » Fri Jan 25, 2013 2:13 am UTC

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
I love deadlines. I love that wooshing sound they make as they fly by. -Douglas Adams

User avatar
PM 2Ring
Posts: 3715
Joined: Mon Jan 26, 2009 3:19 pm UTC
Location: Sydney, Australia

Re: continuing loop until input (python)

Postby PM 2Ring » Fri Jan 25, 2013 7:14 am UTC

That thread-based solution is rather neat, and more compact than the multi-platform code in this thread.

Derek
Posts: 2181
Joined: Wed Aug 18, 2010 4:15 am UTC

Re: continuing loop until input (python)

Postby Derek » Fri Jan 25, 2013 12:15 pm UTC

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.

>-)
Posts: 527
Joined: Tue Apr 24, 2012 1:10 am UTC

Re: continuing loop until input (python)

Postby >-) » Sat Jan 26, 2013 3:36 am UTC

unfortunately, curses doesn't work on windows. i think i'll use zabaron's solution. thanks everyone.

Derek
Posts: 2181
Joined: Wed Aug 18, 2010 4:15 am UTC

Re: continuing loop until input (python)

Postby Derek » Sat Jan 26, 2013 5:08 pm UTC

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.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: continuing loop until input (python)

Postby ahammel » Sun Jan 27, 2013 7:02 pm UTC

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.
He/Him/His/Alex
God damn these electric sex pants!

sje46
Posts: 4730
Joined: Wed May 14, 2008 4:41 am UTC
Location: New Hampshire

Re: continuing loop until input (python)

Postby sje46 » Wed Nov 13, 2013 12:00 am UTC

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.
General_Norris: Taking pride in your nation is taking pride in the division of humanity.
Pirate.Bondage: Let's get married. Right now.

User avatar
skeptical scientist
closed-minded spiritualist
Posts: 6142
Joined: Tue Nov 28, 2006 6:09 am UTC
Location: San Francisco

Re: continuing loop until input (python)

Postby skeptical scientist » Wed Nov 13, 2013 2:05 am UTC

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.
I'm looking forward to the day when the SNES emulator on my computer works by emulating the elementary particles in an actual, physical box with Nintendo stamped on the side.

"With math, all things are possible." —Rebecca Watson

madaco
Posts: 165
Joined: Sat Feb 13, 2010 11:25 pm UTC

Re: continuing loop until input (python)

Postby madaco » Wed Dec 18, 2013 12:50 am UTC

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.
I found my old forum signature to be awkward, so I'm changing it to this until I pick a better one.

>-)
Posts: 527
Joined: Tue Apr 24, 2012 1:10 am UTC

Re: continuing loop until input (python)

Postby >-) » Fri Dec 27, 2013 12:24 pm UTC

It (referring to some of the multiprocessing examples), doesn't work from the interpreter if you're testing from that. post your code.

madaco
Posts: 165
Joined: Sat Feb 13, 2010 11:25 pm UTC

Re: continuing loop until input (python)

Postby madaco » Sat Jan 11, 2014 11:05 pm UTC

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)
I found my old forum signature to be awkward, so I'm changing it to this until I pick a better one.

sonicspin
Posts: 73
Joined: Wed Oct 24, 2012 2:17 am UTC

Re: continuing loop until input (python)

Postby sonicspin » Sun Jan 12, 2014 10:51 pm UTC

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)

User avatar
Zabaron
Posts: 113
Joined: Wed Jun 04, 2008 3:33 am UTC
Location: Georgia

Re: continuing loop until input (python)

Postby Zabaron » Thu Jan 16, 2014 12:32 am UTC

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
I love deadlines. I love that wooshing sound they make as they fly by. -Douglas Adams


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 7 guests