Python allows us to set up signal -handlers so when a particular signal arrives to our program we can have a behavior different from the default.

For example when you run a program on the terminal and press Ctrl-C the default behavior is to quit the program.

In this example we override that behavior and instead we ask the user if s/he really want to quit or if we can continue running.

This can be useful in all kinds of situations. For example a long-running process that somehow knows how much more time is needed can ask the user if s/he really wants to abandon the process at this point or return to processing.

This is how it works:

Catching Ctrl-c

The first thing is to create a function that will be executed when the specific signal arrives.

Then we use the signal.signal call to connect a specific signal to a specific function.

From that point on this is going to be the behavior.

In this example we also use the "magic" of printing carriage return ("\r") only and not new line ("\n") so we keep counting in the same row. We also tell the print function to flush the output to the screen immediately and not wait for a newline. Finally we also employ readchar so the python code will be able to react to the pressing of a single button on the keyboard without the need to press ENTER. (That would move us to another line.)

examples/python/ctrl_c.py

import signal
import time
import readchar

def handler(signum, frame):
    msg = "Ctrl-c was pressed. Do you really want to exit? y/n "
    print(msg, end="", flush=True)
    res = readchar.readchar()
    if res == 'y':
        print("")
        exit(1)
    else:
        print("", end="\r", flush=True)
        print(" " * len(msg), end="", flush=True) # clear the printed line
        print("    ", end="\r", flush=True)


signal.signal(signal.SIGINT, handler)

count = 0
while True:
    print(f"{count}", end="\r", flush=True)
    count += 1
    time.sleep(0.1)

Skeleton

A simplified version of the script, that does not include the fancy "keep it in one line" thing:

examples/python/ctrl_c_skeleton.py

import signal
import time

def handler(signum, frame):
    res = input("Ctrl-c was pressed. Do you really want to exit? y/n ")
    if res == 'y':
        exit(1)

signal.signal(signal.SIGINT, handler)

count = 0
while True:
    print(count)
    count += 1
    time.sleep(0.1)

This is how it looks like when the numbers are running out of the screen:

Catching Ctrl-C