6

ユーザーが安全に+KeyboardInterruptを使用して終了できるように、例外をキャッチする Python スクリプトを作成するとします。CtrlC

ただし、すべての重要なアクション (ファイルの書き込みなど) をcatchブロックに入れることはできません。これは、ローカル変数に依存し、その後のCtrl+がブロックCを壊さないようにするためです。

空の ( pass)try部分とその部分内のすべてのコードを含む try-catch ブロックを使用しfinallyて、このスニペットを途中で中断されない可能性のある「アトミックで割り込みセーフなコード」として定義することはうまくいきますか?

例:

try:
    with open("file.txt", "w") as f:
        for i in range(1000000):
            # imagine something useful that takes very long instead
            data = str(data ** (data ** data))
            try:
                pass
            finally:
                # ensure that this code is not interrupted to prevent file corruption:
                f.write(data)

except KeyboardInterrupt:
        print("User aborted, data created so far saved in file.txt")
        exit(0)

この例では、現在生成されているデータ文字列は気にしません。つまり、作成が中断され、書き込みがトリガーされない可能性があります。しかし、書き込みが開始されたら、それを完了する必要があります。それが私が保証したいすべてです。また、finally 句内で書き込みを実行中に例外 (または KeyboardInterrupt) が発生した場合はどうなりますか?

4

2 に答える 2

5

あなたの場合、ファイルの書き込みはアトミックであるため問題はありませんが、より複雑なファイルオブジェクトの実装がある場合はtry-except、間違った場所にあります。書き込みの周りに例外処理を配置する必要があります。

try:
    f.write(data)
except:
    #do some action to restore file integrity
    raise

たとえば、バイナリ データを書き込む場合は、次のようにすることができます。

filepos = f.tell()
try:
    f.write(data)
except:
    # remove the already written data
    f.seek(filepos)
    f.truncate()
    raise
于 2016-04-21T06:34:33.600 に答える
5

コード入力も中断できfinallyます。Python はこれについて保証しません。保証されるのは、スイートが完了した後、またはスイートで例外が発生した場合に、実行がスイートに切り替わることだけです。Aは、スコープ外ではなくスコープ内で発生した例外のみを処理でき、そのスコープ外にあります。finallytrytrytryfinally

そのため、ステートメントで使用しても意味がありません。パスはノーオペレーションであり、中断されることはありませんが、スイートは簡単に中断できます。trypassfinally

別のテクニックを選択する必要があります。別のファイルに書き込み、正常に完了したらその場所に移動できます。たとえば、OS は、ファイルの移動がアトミックであることを保証します。または、最後に成功した書き込み位置を記録し、次の書き込みが中断された場合はその位置までファイルを切り捨てます。または、記録が成功したことを知らせるマーカーをファイルに書き込んで、読み取りが何を無視するかを認識できるようにします。

于 2016-04-21T06:24:37.133 に答える