58

I currently have code that basically runs an infinite while loop to collect data from users. Constantly updating dictionaries/lists based on the contents of a text file. For reference:

while (True):
    IDs2=UpdatePoints(value,IDs2)
    time.sleep(10)

Basically, my problem is that I do not know when I want this to end, but after this while loop runs I want to use the information collected, not lose it by crashing my program. Is there a simple, elegant way to simply exit out of the while loop whenever I want? Something like pressing a certain key on my keyboard would be awesome.

Brian HK
  • 860
  • 1
  • 8
  • 18

6 Answers6

123

You can try wrapping that code in a try/except block, because keyboard interrupts are just exceptions:

try:
    while True:
        IDs2=UpdatePoints(value,IDs2)
        time.sleep(10)
except KeyboardInterrupt:
    print('interrupted!')

Then you can exit the loop with CTRL-C.

Melebius
  • 6,183
  • 4
  • 39
  • 52
Steve Howard
  • 6,737
  • 1
  • 26
  • 37
  • 2
    I've got to say, this is one of the neater uses for a try/except block I've seen. I might try this pattern for debugging. – reem Sep 25 '13 at 02:36
  • 11
    try... except... blocks are not only for "stuff that isn't supposed to happen". In fact, ["Python generally recommends the EAFP policy"](http://legacy.python.org/dev/peps/pep-0463/) (easier to ask forgiveness than permission) – Alex Alifimoff Feb 15 '17 at 14:01
  • 1
    @dopatraman I’ve updated the answer for Python 3 compatibility. Please try now. – Melebius Jun 06 '17 at 08:09
  • 1
    Be aware that depending on the IDE you use, Ctrl+C will not work. For example PyDev does not support it. To test this, run the program in a normal console. – user136036 Dec 30 '17 at 00:18
44

You could use exceptions. But you only should use exceptions for stuff that isn't supposed to happen. So not for this.

That is why I recommand signals:

import sys, signal
def signal_handler(signal, frame):
    print("\nprogram exiting gracefully")
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

you should put this on the beginning of your program and when you press ctrl+c wherever in your program it will shut down gracefully

Code explanation:

You import sys and signals. Then you make a function that executes on exit. sys.exit(0) stops the programming with exit code 0 (the code that says, everything went good).

When the program get the SIGINT either by ctrl-c or by a kill command in the terminal you program will shutdown gracefully.

Tristan
  • 2,000
  • 17
  • 32
  • 2
    This worked for me when the try-except did not. Don't know why, and I'm afraid I've not got time to investigate. – WillC Mar 21 '18 at 01:44
  • 1
    @WillC Perhaps this helps: the try-except only defines a way to handle a KeyboardInterrupt once it managed to actually interrupt the program. But the program can still be blocking and not register your interrupt signal. That's where the signal handler is useful: when the corresponding signal arrives, the handler is directly executed regardless - even if your program is blocking/looping in some C code. (for example an expensive regex.match call) – MarkM Aug 01 '19 at 09:07
5

I think the easiest solution would be to catch the KeyboardInterrupt when the interrupt key is pressed, and use that to determine when to stop the loop.

except KeyboardInterrupt:
    break

The disadvantage of looking for this exception is that it may prevent the user from terminating the program while the loop is still running.

eandersson
  • 25,781
  • 8
  • 89
  • 110
2

I use python to track stock prices and submit automated buy/sell commands on my portfolio. Long story short, I wanted my tracking program to ping the data server for info, and place trades off of the information gathered, but I also wanted to save the stock data for future reference, on top of being able to start/stop the program whenever I wanted.

What ended up working for me was the following:

trigger = True
while trigger == True:
 try:
  (tracking program and purchasing program conditions here)
 except:
  trigger = False

print('shutdown initialized')
df = pd.DataFrame...
save all the datas
print('shutdown complete')

etc.

From here, while the program is in the forever loop spamming away requests for data from my broker's API, using the CTRL-C keyboard interrupt function toggles the exception to the try loop, which nullifies the while loop, allowing the script to finalize the data saving protocol without bringing the entire script to an abrupt halt.

Hope this helps!

Resultant

GabrieleMartini
  • 1,665
  • 2
  • 19
  • 26
Michael Green
  • 719
  • 6
  • 15
0

I would suggest using the try, except syntax within a loop if you are running on an IPYNB file in Google Colab or Jupyter, like:

while True:
    try:
       IDs2=UpdatePoints(value,IDs2)
       time.sleep(10)
    except KeyboardInterrupt:
       break
    except:
       continue

the last except is for any other error if occurs the loop will resume

-5

You can catch the KeyboardInterrupt error in Python:

try:
    while 1>0:
        IDs2=UpdatePoints(value,IDs2)
        time.sleep(10)
except KeyboardInterrupt:
    print('While loop ended!')

To read more about Python Error handling (try, except, etc.):

https://www.w3schools.com/python/python_try_except.asp

or:

https://www.w3schools.com/python/gloss_python_try_finally.asp

topsoftwarepro
  • 773
  • 5
  • 19
  • 1
    How on Earth this could be more professional if you just obfuscating boolean for no reason? – Divelix Mar 15 '23 at 09:30
  • I'm not sure how the innards of Python works, but as such it looks like wasted CPU cycles to me, aside from being less readable. – Eyso Apr 20 '23 at 12:10