try...except...finally
ステートメントでfinally
が必要な理由がわかりません。私の意見では、このコードブロック
try:
run_code1()
except TypeError:
run_code2()
other_code()
finally
を使用するこれと同じです:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
何か不足していますか?
早めに戻ると違いがあります:
try:
run_code1()
except TypeError:
run_code2()
return None # The finally block is run before the method returns
finally:
other_code()
これと比較してください:
try:
run_code1()
except TypeError:
run_code2()
return None
other_code() # This doesn't get run if there's an exception.
違いを引き起こす可能性のある他の状況:
run_code1()
で例外がスローされたが、TypeError
ではない場合。continue
およびbreak
ステートメントなどの他の制御フローステートメント。finally
を使用すると、例外をキャッチしなくても、例外が発生したかどうかに関係なく、ファイルまたはリソースが閉じられたり解放されたりすることができます。(または、specific例外をキャッチしない場合)
myfile = open("test.txt", "w")
try:
myfile.write("the Answer is: ")
myfile.write(42) # raises TypeError, which will be propagated to caller
finally:
myfile.close() # will be executed before TypeError is propagated
この例では、with
ステートメントを使用した方が良いでしょうが、この種の構造は他の種類のリソースに使用できます。
数年後、読者が面白いと感じるかもしれないfinally
の悪用について ブログ投稿 を書きました。
それらは同等ではありません。最後に、他に何があってもコードが実行されます。実行する必要があるクリーンアップコードに役立ちます。
上記の他の回答に追加するために、finally
句は例外が発生しなかった場合にのみ実行されるのに対して、else
句は実行されます。
たとえば、例外なしでファイルに書き込むと、以下が出力されます:
file = open('test.txt', 'w')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
出力:
Writing to file.
Write successful.
File closed.
例外がある場合、コードは次を出力します(意図的なエラーはファイルを読み取り専用にしておくことに注意してください。
file = open('test.txt', 'r')
try:
file.write("Testing.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
出力:
Could not write to file.
File closed.
finally
句が例外に関係なく実行されることがわかります。お役に立てれば。
コードブロックは同等ではありません。 run_code1()
がfinally
以外の例外をスローした場合、またはrun_code2()
が例外をスローした場合、TypeError
句も実行されますが、これらの場合、最初のバージョンのother_code()
は実行されません。
最初の例では、run_code1()
がTypeError
ではない例外を発生させた場合はどうなりますか? ... other_code()
は実行されません。
それをfinally:
バージョンと比較してください:other_code()
は、発生する例外に関係なく実行されることが保証されています。
finally
は"clean up actions"を定義するためのものです。 finally
句は、例外を処理しなくても例外が発生したかどうかに関係なく、try
ステートメントを終了する前にイベントで実行されます。
2番目の@Byersの例。
最後に、メイン作業用のコードを実行する前に「オプション」コードを実行したい場合にも使用できます。そのオプションコードはさまざまな理由で失敗する可能性があります。
次の例では、store_some_debug_info
がどのような例外をスローするか正確にはわかりません。
実行できます:
try:
store_some_debug_info()
except Exception:
pass
do_something_really_important()
しかし、ほとんどのリンターは、あまりにもあいまいな例外をキャッチすることに文句を言うでしょう。また、エラーに対してpass
だけを選択しているため、except
ブロックは実際には値を追加しません。
try:
store_some_debug_info()
finally:
do_something_really_important()
上記のコードは、コードの最初のブロックと同じ効果がありますが、より簡潔です。
完璧な例は次のとおりです。
try:
#x = Hello + 20
x = 10 + 20
except:
print 'I am in except block'
x = 20 + 30
else:
print 'I am in else block'
x += 1
finally:
print 'Finally x = %s' %(x)
デルファイを数年間専門的に使用することで、最終的に使用するクリーンアップルーチンを保護することができました。 Delphiでは、メモリリークが発生しないように、tryブロックの前に作成されたリソースをクリーンアップするために、finallyの使用をほぼ強制しています。これは、Java、Python、およびRubyの動作方法でもあります。
resource = create_resource
try:
use resource
finally:
resource.cleanup
リソースは、試行と最終の間に何をするかに関係なくクリーンアップされます。また、実行がtry
ブロックに到達しない場合、クリーンアップされません。 (つまり、create_resource
自体が例外をスローします)コードを「例外安全」にします。
最終ブロックが実際に必要な理由については、すべての言語が必要なわけではありません。 C++では、例外がスタックを展開したときにクリーンアップを強制するデストラクタを自動的に呼び出しました。私はこれがtry ... finally言語と比較してよりクリーンなコードの方向へのステップアップだと思います。
{
type object1;
smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.
documentation で説明したように、finally
句は、すべての状況下で実行する必要があるクリーンアップアクションを定義することを目的としています。
finally
が存在する場合、「クリーンアップ」ハンドラーを指定します。try
句とexcept
句を含むelse
句が実行されます。いずれかの句で例外が発生し、処理されない場合、例外は一時的に保存されます。finally
句が実行されます。保存された例外がある場合は、finally
句の最後で再発生します。
例:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
ご覧のとおり、finally
句はどのイベントでも実行されます。 2つの文字列を分割することで発生するTypeError
はexcept
句で処理されないため、finally
句の実行後に再発生します。
実際のアプリケーションでは、finally節は、リソースの使用が成功したかどうかに関係なく、外部リソース(ファイルやネットワーク接続など)を解放するのに役立ちます。
Tryブロックには、tryステートメントという必須の句が1つだけあります。 except、else、finally節はオプションであり、ユーザー設定に基づいています。
finally:Pythonはtryステートメントを終了する前に、プログラムを終了している場合でも、あらゆる条件下でfinallyブロックのコードを実行します。たとえば、exceptブロックまたはelseブロックでコードを実行中にPythonでエラーが発生した場合、finallyブロックはプログラムを停止する前に実行されます。