3

I want to be able to end my program after I run at any point of time. Similar to how I press ctrl + c and it says keyboard interrupt but I don't want something like

if "keyboard press here" == true:
  quit()

the reason I don't want it to be like above is because it seems that my code will run until it reaches this part of my code. Is there a command

edit:

Sorry, if I'm not clear on my question. What I mean is that I don't want my program to have to reach the point of where it says "press keyboard to quit" in my program but to have it in every space. so for example if I have a while loop that looks something like this:

while True
print "1"
print "2"
if "keyboard press here" == true:
      quit()
print "3"
print "4"

I'd have to wait till it prints out

>>>1
>>>2

before it I can press my keyboard to stop or if it passes 2 and goes to print 3 it'd look like this

>>>1
>>>2
>>>3
>>>4
>>>1
>>>2

and then my program will stop.

I'd like to have my program work like this:

while True
    print "1"
    if "keyboard press here" == true:
          quit()
    print "2"
    if "keyboard press here" == true:
          quit()
    print "3"
    if "keyboard press here" == true:
          quit()
    print "4"
    if "keyboard press here" == true:
          quit()

but I don't want to keep putting

if "keyboard press here" == true: quit()

every other space. Is there a way to do that?

aWLW
  • 189
  • 1
  • 8
  • 1
    You can handle the `KeyboardInterrupt` exception and silently exit instead. – Martijn Pieters Aug 26 '14 at 18:03
  • 1
    I don't understand. If you want your program to be able to exit whenever it wants, you know how to do that. If you want to be able to kill the program from the terminal, you know how to do that. Are you looking for a way to kill it from outside of the terminal that launched it? If so, that has nothing to do with Python, and everything to do with your OS—you do it the same way you do any other program, with a `kill` or `pskill` command or a Task Manager or Activity Monitor GUI, etc. – abarnert Aug 26 '14 at 18:05
  • OK now whats your question ? – Mazdak Aug 26 '14 at 18:06
  • 1
    You could create a `signal_handler` method and capture the SIGINT thrown from a `ctrl+c` and then do any cleanup/output you wish. This can be done at the beginning of the program. See http://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python –  Aug 26 '14 at 18:09
  • 2
    The confusing part of your question is that ctrl-c already does what you want out of the box without you needed to code anything. Why isn't that good enough? Do you want to quit on any keyboard key? Do you want to have a command interface plus an exit keyword? – tdelaney Aug 26 '14 at 18:37
  • @tdelaney is right, ctrl-c really does is exactly what you want (based on your description). I updated my answer according to your updated question. Hope that it is helpful! –  Aug 26 '14 at 21:35

5 Answers5

3

Hm, it isn't pretty, but all I can think of is really handling the keyboard interrupts...

while True:
    try:
        # your main code here   
    except KeyboardInterrupt:
        break # or quit(), or sys.exit()

Edit:

To answer your updated question:

What I mean is that I don't want my program to have to reach the point of where it says "press keyboard to quit" in my program but to have it in every space

Well, you don't have to, the try-except does exactly what you want. To apply this code to your updated answer:

while True:
    try:
        print "1"
        print "2"
        print "3"
        print "4"
    except KeyboardInterrupt:
        break
2

You can create a signal handler, or override with your own excepthook.

Signal Handler

A signal handler may help.

import sys
import signal


def terminate(signal, frame):
    print("received SIGINT, exit..." file=sys.stderr)
    sys.exit(0)

signal.signal(signal.SIGINT, terminate)

for i in range(0, 100000):
    print(i)

But be careful with the signal handler, you should write your signal handler very very carefully. It is really hard to write a correct signal handler even for a experienced UNIX C programmer.

When a program received a signal, it will be paused ungracefully.

For example, print() blocks a stream or IO device while it is working, when a signal generated, it will be paused in order to execute the signal handler. This time, So you can't call (reentrant) print() when current print() does not return yet because it is still holding the stream/device.

Even worse, the signal will be triggered when the current signal handler is still running. So, the signal handler and all the functions must allow reentrant calls.

But it is easier and safer in Python, because Python did all necessary works to allow core functions to reentry.

Exception Hook

Where are trackback errors come from? Python will call a special function (sys.__excepthook__) to print the trackback when there is an unhandled exception.

You could override it and do anything extra (except to raise an unhandled exception to avoid infinite recursion ^_^), and you don't need to think about the reentrant problem.

We often use this feature to write down the error to a logfile or popup a warning window. But it works for your situation.

import sys


def my_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        print("got KeyboardInterrupt, exit...")
        sys.exit(0)
    else:
        # call the original hook to print the trackback properly
        sys.__excepthook__(type, value, traceback)

sys.excepthook = my_excepthook

for i in range(0, 100000):
    print(i)

BTW, a warning, these two methods are applicable for multithreading programming, but you need to do more than the examples, and be more careful.

比尔盖子
  • 2,693
  • 5
  • 37
  • 53
0

To do what you want your code is going to have to be running in an infinate loop, whether or not this is practical depends on the kind of program you're writing.

Assuming this code is in an infinate loop and you dont have any sleep times that would slow it down, just do pretty much what you put above.

You are correct in that the program will have to reach that point of execution before the statement takes effect, but because you are in an infinate loop which is running extremely fast, the time will seem instantaneous to the user.

EDIT: depending on the size of the loop and whether or not your program is going to be sleeping for any significant amount of time, you may find the need to put the conditional in multiple places within your loop.

(most likely once at the top and then once after every sleep)

Further editied in response to comments 1 & 2 on this answer:
What i would do in your case is :

 flag=False
 while True:
      if flag:
         quit() # or break or whatever you want to do

      print 1
      print 2
      #press to continue function to prompt and get key press/ set variable goes here....
      if pressed:
         flag=True
         continue
      print 3 
      print 4
      .....

telling the program "continue" will make it begin the next loop itteration immediately bur since you have set the flag, the program will not run .

However, I am not sure I am fully understanding what you want since under this logic, you could simply put:

if pressed:
   sys.exit()

I realize what you want now, and your just going to want to handle the interrupts with an exception, like sebastian said, or use a signal handler like others have suggested

Luke
  • 5,567
  • 4
  • 37
  • 66
  • ya, I have everything within a loop but if possible I'd like it to just stop at the moment of time I tell it because it'll still finish its the rest of the code even if it seems instantaneous. An example of what I meant is: print "1" , print "2", "press to quit here", print "3", print "4". If I were to press to quit and my program prints 1,2,3 it'll still print "4" and loop back to print "1", "2" before stopping so, I'd have 1,2,3,4,1,2 unless if I put a press to quit every second space in my program but then this will be a very big program. – aWLW Aug 26 '14 at 18:23
  • then you can either set a flag when they press it and tell your program to only print the numbers if the flag isnt set, OR, depending on the way your program is setup you can do what i point out in my newest edit (give me a second to add it in real quick) – Luke Aug 26 '14 at 18:50
0

As near as I can tell, you want to be able to terminate your program in a manner similar to ctrl-c but using a different keyboard sequence. One way to do this is to put your stdin reader into a different thread and have it kill its own program. The main thread can catch KeyboardInterrupt so that you don't get a python stack trace at the end.

import os
import sys
import threading
import time
import signal

def kill_handler():
    data = sys.stdin.read(1)
    os.kill(os.getpid(), signal.SIGINT)

def main():
    kill_thread = threading.Thread(target=kill_handler)
    kill_thread.daemon = True
    kill_thread.start()

    print "press enter to terminate"
    try:
        while True:
            print 1
            time.sleep(.5)
            print 2
            time.sleep(.5)
            print 3
            time.sleep(.5)
            print 4
            time.sleep(.5)
    except KeyboardInterrupt:
        print "terminating"

if __name__=='__main__':
    main()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

I think the behavior that you want is to have your program stop after every step and ask you whether you want to continue?

A really dirty way to do this would be to run your program from within pdb, the python debugger. Set a breakpoint at the top of your program, or on the first line of your loop:

import pdb
pdb.set_trace()

Then, when you execute the program, you'll be taken to the pdb prompt. At each step, you can enter 'next' or 'n' to proceed. If you want to exit the debugger and let the program finish naturally, enter 'c' (for 'continue'). And if you want to quit, enter ctrl+D.

If this program is for your personal use, that'll be an easy way to get what you want. If you plan on distributing it, though, then it's obviously out of the question.

geekofalltrades
  • 214
  • 1
  • 10