How do I capture SIGINT in Python?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
SIGINT is the signal normally sent when a user presses Ctrl+C in a terminal. In Python, the usual way to capture it is with the signal module so the program can shut down cleanly instead of terminating abruptly.
The main idea is simple: register a handler function for signal.SIGINT, do whatever cleanup is necessary, and then exit or let the program stop in a controlled way.
Register a Signal Handler
A minimal example looks like this:
When Ctrl+C is pressed, Python runs handle_sigint instead of immediately exiting with the default behavior.
Use It for Cleanup
The real value of capturing SIGINT is cleanup. For example, you may want to close a file, stop a worker, or flush some state:
This pattern is often better than calling sys.exit directly inside the handler, because it lets the main loop exit on its own terms.
Remember the Main-Thread Rule
In CPython, signal handlers are executed in the main thread. That means signal handling is best used to set flags or trigger shutdown logic that the main flow can observe.
If you have worker threads, the usual pattern is:
- catch
SIGINTin the main thread - set a shutdown flag or event
- let worker threads notice that state and stop gracefully
Trying to do too much directly inside the handler is usually unnecessary.
KeyboardInterrupt Is Related but Different
Another common approach is to catch KeyboardInterrupt:
This is often enough for small scripts. The signal module becomes more useful when you want explicit signal wiring or a more centralized shutdown path.
Keep the Handler Simple
Signal handlers should stay small. Printing a message, setting a flag, or writing minimal cleanup state is reasonable. Heavy logic inside the handler can make shutdown behavior harder to reason about.
In many cases, the handler should only tell the rest of the program that shutdown has been requested.
Signals Work Best with Cooperative Shutdown
The cleanest shutdowns happen when the signal handler only marks intent and the main program does the real cleanup work. That keeps signal handling predictable even when the program grows beyond a tiny script.
Test It in a Real Terminal
Signal handling is easiest to verify in an actual terminal session where Ctrl+C produces the expected interrupt. Some notebook or IDE environments behave differently, so terminal testing is the clearest baseline.
Common Pitfalls
- Doing large amounts of work directly inside the signal handler.
- Forgetting that signal handlers run in the main thread.
- Expecting Windows and Unix signal behavior to be identical in every detail.
- Confusing
KeyboardInterrupthandling with explicit signal registration. - Capturing
SIGINTbut never actually changing the main loop behavior.
Summary
- Use
signal.signal(signal.SIGINT, handler)to captureCtrl+Cexplicitly. - Keep the handler small and let the main program shut down cleanly.
- Use a flag or event when background work needs to stop gracefully.
- For simple scripts,
KeyboardInterruptmay be enough. - Signal handling is most useful when cleanup matters more than immediate termination.

