112

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

Ctrlユーザーが+を押した場合、トレースなしでクリーンに終了したいC

4

6 に答える 6

160

はい、モジュールシグナルを使用して割り込みハンドラーをインストールし、 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()
于 2010-11-17T14:30:36.523 に答える
40

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

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


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

(はい、これが質問に直接答えないことは知っていますが、try /exceptブロックが必要なことが好ましくない理由は明確ではありません-おそらくこれによりOPの煩わしさが軽減されます)

于 2010-11-17T14:32:56.443 に答える
32

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

>>> 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

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

于 2010-11-17T15:18:34.103 に答える
8

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

ファブリック操作のコンテキストで終了後のクリーンアップを実行したいので、すべてを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ハンドラーは例外をキャッチし、コールバックを呼び出してから、再レイズします。その例外。しかし、これは別の方法で行うことができます。)

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

于 2013-11-05T14:15:54.377 に答える
4

を置き換えることで、(最も明白でおそらく「最良の」解決策ですが、すでにそれを知っていて、何か他のものを求めている)KeyboardInterruptなしで、のスタックトレースを印刷することを防ぐことができます。何かのようなものtry: ... except KeyboardInterrupt: passsys.excepthook

def custom_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        return # do nothing
    else:
        sys.__excepthook__(type, value, traceback)
于 2010-11-17T14:27:39.287 に答える
3

提案された解決策をみんなで試しましたが、実際に機能させるには、自分でコードを即興で作成する必要がありました。以下は私の即興のコードです:

import signal
import sys
import time

def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    print(signal) # Value is 2 for CTRL + C
    print(frame) # Where your execution of program is at moment - the Line Number
    sys.exit(0)

#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)

# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True 
while timeLoopRun:  
    time.sleep(1)
    if secondsCount < 1:
        timeLoopRun = False
    print('Closing in '+ str(secondsCount)+ ' seconds')
    secondsCount = secondsCount - 1
于 2020-05-14T20:11:41.820 に答える