Python では「finally」は常に実行されますか? 質問する

Python では「finally」は常に実行されますか? 質問する

Python のあらゆる try-finally ブロックでは、そのfinallyブロックが常に実行されることが保証されていますか?

たとえば、exceptブロック内で return するとします。

try:
    1/0
except ZeroDivisionError:
    return
finally:
    print("Does this code run?")

あるいは、 をリレイズするかもしれませんException:

try:
    1/0
except ZeroDivisionError:
    raise
finally:
    print("What about this code?")

テストではfinally上記の例が実行されることが示されていますが、私が考えていない他のシナリオもあると思います。

finallyPython でブロックの実行が失敗するシナリオはありますか?

ベストアンサー1

「保証」という言葉は、 のどの実装にもふさわしいものよりはるかに強い言葉です。保証されているのは、実行が-構造finally全体から流れ出る場合、それを実行するには を通過するということです。保証されていないのは、実行が-から流れ出ることです。tryfinallyfinallytryfinally

  • finallyジェネレータまたは非同期コルーチン内のA は実行されない可能性がありますオブジェクトが最後まで実行されない場合。これが発生する原因は多数考えられますが、その 1 つを次に示します。

    def gen(text):
        try:
            for line in text:
                try:
                    yield int(line)
                except:
                    # Ignore blank lines - but catch too much!
                    pass
        finally:
            print('Doing important cleanup')
    
    text = ['1', '', '2', '', '3']
    
    if any(n > 1 for n in gen(text)):
        print('Found a number')
    
    print('Oops, no cleanup.')
    

    この例は少しトリッキーであることに注意してください。ジェネレータがガベージ コレクションされると、Python は例外finallyをスローしてブロックを実行しようとしますGeneratorExitが、ここではその例外をキャッチしてからyield再度キャッチし、その時点で Python は警告 ("generator ignore GeneratorExit") を出力して処理を中止します。PEP 342 (拡張ジェネレータによるコルーチン)詳細については。

    ジェネレーターまたはコルーチンが最後まで実行されない可能性があるその他の状況としては、オブジェクトが GC されない場合 (はい、CPython でも可能です)、async with await内の sの場合__aexit__、またはオブジェクトがブロック内のawaits またはs の場合などがあります。このリストは網羅的なものではありません。yieldfinally

  • finallyデーモンスレッド内のAは実行されない可能性があるデーモン以外のスレッドがすべて最初に終了した場合。

  • os._exit直ちにプロセスを停止しますブロックを実行せずにfinally

  • os.forkfinallyブロックを引き起こす可能性があります実行する2回2回発生すると予想される通常の問題だけでなく、共有リソースへのアクセスが適切に行われていない場合、同時アクセスの競合(クラッシュ、停止など)が発生する可能性があります。正しく同期

    multiprocessingワーカープロセスを作成するためにfork-without-execを使用するので、フォーク開始方法(Unix のデフォルト)、os._exitワーカーのジョブが完了するとワーカーを呼び出しますが、finally相互multiprocessing作用が問題になることがあります ()。

  • C レベルのセグメンテーション エラーにより、finallyブロックの実行が妨げられます。
  • kill -SIGKILLブロックの実行を防止しますfinallySIGTERMおよびも、シャットダウンを自分で制御するハンドラーをインストールしない限り、ブロックの実行をSIGHUP防止します。デフォルトでは、Python はまたは を処理しません。finallySIGTERMSIGHUP
  • の例外によりfinallyクリーンアップが完了できない場合があります。特に注目すべきケースは、ユーザーがコントロール+Cを押した場合です。ただブロックの実行を開始するとfinally、Python は を発生させKeyboardInterrupt、ブロックの内容の各行をスキップしますfinally。( KeyboardInterrupt-safe コードを書くのは非常に困難です)。
  • コンピュータの電源が切れたり、休止状態になって起動しなくなったりすると、finallyブロックは実行されません。

ブロックfinallyはトランザクション システムではありません。アトミック性の保証などは一切提供されません。これらの例のいくつかは明白に思えるかもしれませんが、そのようなことが起こる可能性があることを忘れ、finally過度に頼りにしがちです。

おすすめ記事