4

私は Project Euler のコーディングの問題を数多く扱っており、Python は私の頼りになる言語です。通常、多くのプログラムは完了するまでに永遠に時間がかかります。そのため、プログラムの状態に関する診断情報を提供するのに役立つ何かを実装することに取り組んでいます。何かがKeyboardInterrupt発生したときに、プログラムが実行されている時間といくつかの情報を出力できるようにしたいと考えています。まだどれくらい時間がかかるかを把握するのに役立ちます。

これに関する問題は、KeyboardInterruptヒットしたときにCtrl-Cプログラムを終了することです...そして、このコードの構造、またはPythonでまだ見つけていない何かと関係があると思います.

KeyboardInterruptがキャッチされた直後に同じ行でコードを再開したい。

このコードがどのように見えるかの例を次に示します。

     try:
         ...
         ...
         ... #I interrupt code here and hopefully keep going!
         ...
         ...
     except KeyboardInterrupt:
         ...
     finally:
         ...

誰かがこれを行う目的を理解し、これを行う方法を見つけたり、実行中のコードからブレークを呼び出すこの醜い方法を回避したりするのを手伝ってくれることを願っています。

4

2 に答える 2

5

一般に、try ブロック内で例外がトリガーされた後、特定のコード セグメントに実行を戻すことはできません。例外は、他のスレッドの他の副作用の影響を受ける他の多くの状態の深い場所で発生する可能性があるためです。Python でこれを許可する一般的な解決策がないことを考えると、これはおそらくあなたのプログラムには当てはまりませんが、例外処理を使用してやりたいことは基本的に不可能です。

ただし、SIGINTシグナルのデフォルトのハンドラーは例外をスローするKeyboardInterruptことです。それを乗っ取って別のことを行うことができれば、実質的にこれを実現できます。以下に簡単なプログラムを示します。

import signal
import pdb

def signal_handler(signal, frame):
    pdb.set_trace()

signal.signal(signal.SIGINT, signal_handler)

count = 0
while True:
    count += 1

SIGINTハンドラーは、現在のフレームでデバッガーを呼び出す単なる関数になり、Ctrl-C が押されるたびに、コードがあるフレーム内の正確なポイントでデバッガーが起動されます。もちろん、次のように単純に値を検査することもできます。

$ python /tmp/script.py 
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) u
> /tmp/script.py(10)<module>()
-> while True:
(Pdb) pp count
13321869
(Pdb) c
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) quit
Traceback (most recent call last):
...
    if self.quitting: raise BdbQuit
bdb.BdbQuit

そのため、ctrl-c が実行された後にデバッガーが起動しu、ループが実行されていたフレーム (この場合はコード) に p をステップ実行し、実行を続け、再度強制終了し、(入力して)c悪い終了をトリガーしました。quitプログラムを終了します。これを組み込むと、基本的にいつでも中断して、どこでもプログラムの値を調べることができます。

于 2016-06-28T04:39:36.523 に答える
1

「うん」ハリーが言った。"の 。. . すぐに。私はこれを片付けるだけです。彼は床に落ちた砕いたボウルを指差した。ロンはうなずいて立ち去った。「レパロ」ハリーはつぶやき、壊れた破片に杖を向けた。 それらは一緒に飛んで戻ってきた。-ハリー・ポッターと不死鳥の騎士団

キーボード割り込みが発生するとすぐに、その情報は失われます。try/catch によってプログラムは回復できますが、それ以前に行われていたことは永久に失われます[1]

幸いなことに、キーボード割り込みは実際には c レベルのシグナルです。必要に応じて、個別にインターセプトして処理することができ ます。tracebackおよびintrospectモジュールが役立つはずです

単純なハックの場合は、それで問題ありませんが、シグナルドキュメントからのこのコメントに基づいて、一般的に使用することには注意が必要です(実装に依存):

一部の実装では、キーボードによって生成されたシグナル (SIGINT など) がすべてのスレッド (SGI など) に配信される一方で、他の実装 (Solaris など) では、そのようなシグナルは 1 つのランダムなスレッドに配信されるという問題が残っています (中間の可能性としては、メインスレッドに配信します -- POSIX?)。今のところ、3 つのケースすべてで機能する実用的な実装があります。getpid() がメイン スレッドと同じでない場合、ハンドラーはシグナルを無視します。XXX これはハックです。


脚注

[1]わかりました、いいえ、そうではありません。Python で何かを行うのに十分なイントロスペクションを使用できますが、それはひどい考えであり、私の引用には合いません。あなたが本当に何かひどいことをしたいのなら、これらの人々があなたのためにそれをやった: https://github.com/ajalt/fuckitpy

于 2016-06-28T04:41:46.880 に答える