web-dev-qa-db-ja.com

try-exceptなしでPythonでキーボード割り込みをキャプチャする

PythonにKeyboardInterruptイベント内のすべてのコードをtry-exceptステートメントに入れずにキャプチャする方法はありますか?

ユーザーが押すとトレースなしできれいに終了したい Ctrl+C

98
Alex

はい、モジュール signal を使用して割り込みハンドラーをインストールし、 threading.Event を使用して永久に待機できます。

import signal
import sys
import time
import threading

def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()
143
Johan Kotlinski

トレースバックを表示したくない場合は、次のようにコードを作成します。

## all your app logic here
def main():
   ## whatever your app does.


if __== "__main__":
   try:
      main()
   except KeyboardInterrupt:
      # do nothing here
      pass

はい

34
bgporter

独自のシグナルハンドラを設定する代わりに、コンテキストマネージャを使用して例外をキャッチし、無視することもできます。

>>> class CleanExit(object):
...     def __enter__(self):
...             return self
...     def __exit__(self, exc_type, exc_value, exc_tb):
...             if exc_type is KeyboardInterrupt:
...                     return True
...             return exc_type is None
... 
>>> with CleanExit():
...     input()    #just to test it
... 
>>>

これにより、try-exceptブロックが削除されますが、何が起こっているのかについての明示的な言及は保持されます。

これにより、毎回シグナルハンドラを再度設定およびリセットすることなく、コードの一部でのみ割り込みを無視できます。

28
Bakuriu

これは古い質問ですが、最初にここに来てatexitモジュールを発見しました。クロスプラットフォームの実績や警告の完全なリストについてはまだ知りませんが、これまでのところ、Linuxでpost _KeyboardInterruptクリーンアップを処理しようとして探していたものです。別の方法で問題にアプローチしたかっただけです。

Fabric操作のコンテキストで終了後のクリーンアップを行いたいので、try/exceptですべてをラップすることも私にとっては選択肢ではありませんでした。 atexitは、コードが制御フローの最上位にないような状況に適していると思われます。

atexitは、すぐに使用できる非常に優れた機能を備えています。次に例を示します。

import atexit

def goodbye():
    print "You are now leaving the Python sector."

atexit.register(goodbye)

それをデコレータとして使用することもできます(2.6以降、この例はドキュメントからのものです):

import atexit

@atexit.register
def goodbye():
    print "You are now leaving the Python sector."

KeyboardInterruptのみに限定したい場合は、この質問に対する他の人の答えがおそらく良いでしょう。

ただし、atexitモジュールはコードの最大70行であり、例外をコールバック関数に引数として渡すなど、例外を異なる方法で処理する同様のバージョンを作成するのは難しくありません。 (変更されたバージョンを保証するatexitの制限:現在、exit-callback-functionsが例外について知る方法を考えることができません。atexitハンドラーは例外をキャッチし、呼び出しますコールバック(複数可)、その例外を再レイズします。しかし、これを異なる方法で行うことができます。)

詳細については、以下を参照してください。

6
hangtwenty

try: ... except KeyboardInterrupt: pass を置き換えることで、sys.excepthookなしでKeyboardInterruptのスタックトレースを印刷しないようにすることができます(最も明白で適切な「最良の」ソリューションですが、既に知っており、何か他のものを求めています)。何かのようなもの

def custom_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        return # do nothing
    else:
        sys.__excepthook__(type, value, traceback)
4
user395760