2

Let's say I have a python program that is spitting out lines of text, such as:

while 1:
  print "This is a line"

What's the easiest way to allow one to press a key on the keyboard to pause the loop, then to resume if pressed again---but if nothing is pressed it should just continue on automatically?

I'm hoping I don't have to go into something like curses to get this!

mix
  • 6,943
  • 15
  • 61
  • 90
  • 1
    Dupe: http://stackoverflow.com/questions/577467/pause-in-python??? – Preet Sangha Oct 08 '10 at 21:28
  • 1
    @Preet Sangha: I wouldn't say this is a duplicate. The question here is how can you make the program pause when *the user* wants it to and what you are referring to is about making the program pause when *it* wants to. – ktdrv Oct 08 '10 at 21:31
  • Oh ok I stand corrected. – Preet Sangha Oct 08 '10 at 21:50
  • "What's the easiest way..." Always involves actually writing code to actually check the keyboard. What have you tried? Since checking the keyboard varies by OS, what OS are you using? – S.Lott Oct 08 '10 at 22:40

3 Answers3

4

You could try this implementation for Linux / Mac (and possible other Unices) (code attribution: found on ActiveState Code Recipes).

On Windows you should check out msvcrt.

import sys, termios, atexit
from select import select

# save the terminal settings
fd = sys.stdin.fileno()
new_term = termios.tcgetattr(fd)
old_term = termios.tcgetattr(fd)

# new terminal setting unbuffered
new_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO)

# switch to normal terminal
def set_normal_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, old_term)

# switch to unbuffered terminal
def set_curses_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, new_term)

def putch(ch):
    sys.stdout.write(ch)

def getch():
    return sys.stdin.read(1)

def getche():
    ch = getch()
    putch(ch)
    return ch

def kbhit():
    dr,dw,de = select([sys.stdin], [], [], 0)
    return dr <> []

Implementing what you're looking for would then become something like this:

atexit.register(set_normal_term)
set_curses_term()

while True:
    print "myline"
    if kbhit():
        print "paused..."
        ch = getch()
        while True
            if kbhit():
                print "unpaused..."
                ch = getch()
                break
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
2

The easiest way for me, assuming I was working in bash, would be to hit Control-Z to suspend the job, then use the 'fg' command to restore it when I was ready. But since I don't know what platform you're using, I'll have to go with using ChristopheD's solution as your best starting point.

Brian Wisti
  • 159
  • 5
0

When you press Ctrl+C, a KeyboardInterrupt exception gets raised in your program. You can catch that exception to create the behavior you want - for instance, to pause the program and resume after 5s:

import time

while True:
     try:
         # This is where you're doing whatever you're doing
         print("This is a line")
     except KeyboardInterrupt:
         print("Paused! Ctrl+C again within 5 seconds to kill program")
         # A second KeyboardInterrupt that happens during this sleep will
         # not be caught, so it will terminate the program
         time.sleep(5)
         print("Continuing...")

Or to pause the program indefinitely until the user hits 'enter':

while True:
     try:
         # This is where you're doing whatever you're doing
         print("This is a line")
     except KeyboardInterrupt:
         print("Interrupted!")
         input("Press enter to continue, or Ctrl+C to terminate.")
         print("Continuing...")

If you want to catch a second KeyboardInterrupt as well and do something fancy with that, you can do so by nesting try/except blocks, though I wouldn't really recommend that - it's a good idea to allow a string of KeyboardInterrupts to terminate the program.

waterproof
  • 4,943
  • 5
  • 30
  • 28