私はいくつかのプロセスとデータベース接続を開始するpythonスクリプトに取り組んでいます。時々、Ctrl+ C信号でスクリプトを強制終了したいので、クリーンアップを行いたいと思います。
Perlではこれを行います。
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
    print "Caught ^C \n";
    exit (0);
}これをPythonでどうやって行うのですか?
私はいくつかのプロセスとデータベース接続を開始するpythonスクリプトに取り組んでいます。時々、Ctrl+ C信号でスクリプトを強制終了したいので、クリーンアップを行いたいと思います。
Perlではこれを行います。
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
    print "Caught ^C \n";
    exit (0);
}これをPythonでどうやって行うのですか?
回答:
次のsignal.signalようにハンドラを登録します。
#!/usr/bin/env python
import signal
import sys
def signal_handler(sig, frame):
    print('You pressed Ctrl+C!')
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()ここからコードを改造。
詳細ドキュメントはsignal見つけることができるここに。
 
./program.py > output.log。押すとCtrlキーを押しながらCを、あなたのプログラムは、それがすべてのデータファイルがフラッシュされ、それらは、既知の良好な状態で放置されている確認するために、クリーンマークしたことをログに記録させることによって適切に終了します。ただし、Ctrl-CはSIGINTをパイプライン内のすべてのプロセスに送信するため、program.pyが最終ログの印刷を完了する前に、シェルがSTDOUT(現在は「output.log」)を閉じる場合があります。Pythonは「ファイルオブジェクトデストラクタのクローズに失敗しました:sys.excepthookのエラー:」と文句を言います。
                    他と同様に、例外(KeyboardInterrupt)として扱うことができます。新しいファイルを作成し、次の内容でシェルから実行して、意味を確認します。
import time, sys
x = 1
while True:
    try:
        print x
        time.sleep(.3)
        x += 1
    except KeyboardInterrupt:
        print "Bye"
        sys.exit()signal.signal(signal.SIGINT, signal.default_int_handler)。詳細はこちら。
                    そしてコンテキストマネージャとして:
import signal
class GracefulInterruptHandler(object):
    def __init__(self, sig=signal.SIGINT):
        self.sig = sig
    def __enter__(self):
        self.interrupted = False
        self.released = False
        self.original_handler = signal.getsignal(self.sig)
        def handler(signum, frame):
            self.release()
            self.interrupted = True
        signal.signal(self.sig, handler)
        return self
    def __exit__(self, type, value, tb):
        self.release()
    def release(self):
        if self.released:
            return False
        signal.signal(self.sig, self.original_handler)
        self.released = True
        return True使用するには:
with GracefulInterruptHandler() as h:
    for i in xrange(1000):
        print "..."
        time.sleep(1)
        if h.interrupted:
            print "interrupted!"
            time.sleep(2)
            breakネストされたハンドラー:
with GracefulInterruptHandler() as h1:
    while True:
        print "(1)..."
        time.sleep(1)
        with GracefulInterruptHandler() as h2:
            while True:
                print "\t(2)..."
                time.sleep(1)
                if h2.interrupted:
                    print "\t(2) interrupted!"
                    time.sleep(2)
                    break
        if h1.interrupted:
            print "(1) interrupted!"
            time.sleep(2)
            breakここから:https : //gist.github.com/2907502
StopIterationctrl-Cが押されたときに、最も内側のループを解除するためにa をスローすることもできますよね?
                    言及main主な機能として、およびexit_gracefullyとしてのCTRL+のcハンドラ
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        exit_gracefully()私は@udiのコードを複数の信号をサポートするように変更しました(空想はありません):
class GracefulInterruptHandler(object):
    def __init__(self, signals=(signal.SIGINT, signal.SIGTERM)):
        self.signals = signals
        self.original_handlers = {}
    def __enter__(self):
        self.interrupted = False
        self.released = False
        for sig in self.signals:
            self.original_handlers[sig] = signal.getsignal(sig)
            signal.signal(sig, self.handler)
        return self
    def handler(self, signum, frame):
        self.release()
        self.interrupted = True
    def __exit__(self, type, value, tb):
        self.release()
    def release(self):
        if self.released:
            return False
        for sig in self.signals:
            signal.signal(sig, self.original_handlers[sig])
        self.released = True
        return Trueこのコードのサポートキーボード割り込みコール(SIGINT)とSIGTERM(kill <process>)
Matt Jの答えとは対照的に、私は単純なオブジェクトを使用しています。これにより、このハンドラーを解析して、セキュリティで停止する必要のあるすべてのスレッドを処理できる可能性があります。
class SIGINT_handler():
    def __init__(self):
        self.SIGINT = False
    def signal_handler(self, signal, frame):
        print('You pressed Ctrl+C!')
        self.SIGINT = True
handler = SIGINT_handler()
signal.signal(signal.SIGINT, handler.signal_handler)他の場所
while True:
    # task
    if handler.SIGINT:
        breaktime.sleep()変数に対してビジーループを実行する代わりに、イベントを使用する必要があります。
                    Pythonの組み込みシグナルモジュールの関数を使用して、Pythonでシグナルハンドラーを設定できます。具体的には、signal.signal(signalnum, handler)関数はhandlersignal の関数を登録するために使用されsignalnumます。
既存の回答に感謝しますが、追加されました signal.getsignal()
import signal
# store default handler of signal.SIGINT
default_handler = signal.getsignal(signal.SIGINT)
catch_count = 0
def handler(signum, frame):
    global default_handler, catch_count
    catch_count += 1
    print ('wait:', catch_count)
    if catch_count > 3:
        # recover handler for signal.SIGINT
        signal.signal(signal.SIGINT, default_handler)
        print('expecting KeyboardInterrupt')
signal.signal(signal.SIGINT, handler)
print('Press Ctrl+c here')
while True:
    passクリーンアッププロセスが確実に終了するようにしたい場合は、SIG_IGNを使用してMatt Jの回答に追加します。これにより、無視され、クリーンアップが中断されなくなります。SIGINT
import signal
import sys
def signal_handler(signum, frame):
    signal.signal(signum, signal.SIG_IGN) # ignore additional signals
    cleanup() # give your process a chance to clean up
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) # register the signal with the signal handler first
do_stuff()個人的には、ブロックしている標準ソケット(IPC)モードを使用していたため、try / except KeyboardInterruptを使用できませんでした。したがって、SIGINTはキューに入れられましたが、ソケットでデータを受信した後にのみ来ました。
シグナルハンドラの設定も同じように動作します。
一方、これは実際の端末でのみ機能します。他の開始環境はCtrl+を受け入れないCか、シグナルを事前に処理しない場合があります。
また、Pythonには「例外」と「BaseExceptions」があり、インタプリタ自体が完全に終了する必要があるという意味で異なるため、一部の例外は他よりも高い優先順位を持っています(例外はBaseExceptionから派生しています)