JavaScriptを有効にしてください

【Python】プログラムをCtrl+Cで安全に停止させる3つの方法【SIGINT対応】

 ·  ☕ 4 分で読めます

【Python】プログラムをCtrl+Cで安全に停止させる3つの方法【SIGINT対応】

Pythonスクリプトを実行中にCtrl+Cで安全に停止させたい場合、**シグナル(SIGINT)**の正しい扱いが重要です。

try/except KeyboardInterruptで簡潔に捕捉する

🔍 概要

Ctrl+CはPythonにおいてKeyboardInterrupt例外として送出されます。try/exceptでこの例外を捕捉し、終了処理を実装できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
import time

def main():
    try:
        print("処理を開始します。Ctrl+Cで中断可能。")
        while True:
            print("…動作中…")
            time.sleep(1)
    except KeyboardInterrupt:
        print("\nKeyboardInterruptを受け取りました。終了処理を実行します。")
        # 例:一時ファイル削除やDB切断など
    finally:
        print("プログラムを終了します。")

if __name__ == "__main__":
    main()

✅ ポイント

  • シンプルで小規模スクリプトに最適
  • SIGINT(Ctrl+C)のみ対象、他のシグナルには非対応

signal.signalでSIGINTに専用ハンドラを登録

🔍 概要

PythonのsignalモジュールでSIGINTにカスタムハンドラを割り当て、独自のシャットダウン処理を実行できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/usr/bin/env python3
import signal
import sys
import time

def sigint_handler(signum, frame):
    print("\nSIGINTを受信しました。グレースフルシャットダウンを開始します。")
    # 例:ログフラッシュ、ネットワーク切断など
    sys.exit(0)

signal.signal(signal.SIGINT, sigint_handler)

print("処理を開始します。Ctrl+Cで停止します。")
while True:
    print("…動作中…")
    time.sleep(1)

✅ ポイント

  • 複数のシグナル(SIGTERM等)にも拡張可能
  • Webサーバーやデーモンなど中〜大規模向き

現在の処理を完了後、次ループで停止する

🔍 概要

Ctrl+Cを受け取っても現在の処理を完了させ、次ループに入る前に停止します。
バッチ処理や重たい処理を中断せず安全に終わらせたいケースに適します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
import signal
import sys
import time

stop_next = False

def sigint_handler(signum, frame):
    global stop_next
    print("\nCtrl+C受信:現在の処理を完了後、次のループは実行しません。")
    stop_next = True

signal.signal(signal.SIGINT, sigint_handler)

print("Ctrl+Cで次回ループ開始時に停止します")
while True:
    print("…動作中…(現在の処理を継続)")
    time.sleep(2)  # 長時間処理の例
    if stop_next:
        print("停止フラグ検知:ループを抜けて終了します。")
        sys.exit(0)

✅ ポイント

  • 時間のかかる処理を強制終了せずに安全に終えたいときに有効
  • 実行タイミングを明示的に制御できる

使い分けの指針

ケース推奨方法
小規模スクリプトtry/except KeyboardInterrupt
コンテナやデーモンsignal.signalでSIGINT対応
タスクの整合性を保ちたいループ終了制御型

応用テクニック・拡張例

  • ログ連携loggingモジュールを使って、終了原因や実行履歴を記録
  • 複数シグナル対応SIGTERMSIGHUPなどもsignal.signal()で捕捉
  • 非同期処理対応asyncio.get_event_loop().add_signal_handler()を活用
  • マルチスレッド処理threading.Event()と連携し安全にスレッド停止
  • ユニットテストpytestos.kill()等で終了処理の動作確認

参考リンク


まとめ

PythonでCtrl+Cによる停止を安全に扱うには、プログラムの規模・性質に応じた設計が求められます。

それぞれの手法のメリット・制約を理解し、自身のユースケースに最適な方式を選びましょう。

共有

こぴぺたん
著者
こぴぺたん
Copy & Paste Engineer