Pythonに「finally」句が必要なのはなぜですか?


306

私たちが必要とする理由私はわからないfinallytry...except...finallyステートメント。私の意見では、このコードブロック

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

これと同じfinallyです:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

何か不足していますか?

回答:


422

早く帰ったら違いが出ます:

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.

違いを引き起こす可能性があるその他の状況:

  • exceptブロック内で例外がスローされた場合。
  • 例外がスローされてもrun_code1()、それがでない場合TypeError
  • continueand breakステートメントなどの他の制御フローステートメント。

1
try:#x = Hello + 20 x = 10 + 20 except:print 'I am in in except block' x = 20 + 30 else:print 'I am in else block' x + = 1 finally:print 'Finally x =% s '%(x)
Abhijit Sahu

89

を使用finallyして、例外をキャッチしなくても、例外が発生したかどうかに関係なく、ファイルまたはリソースを確実に閉じたり解放したりできます。(または、その特定の例外をキャッチしない場合。)

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


23

それらは同等ではありません。最後に、他に何が起こってもコードが実行されます。実行する必要があるクリーンアップコードに役立ちます。


15
Finally code is run no matter what else happens...無限ループがない限り。またはパワーカット。またはos._exit()。または...
Mark Byers

3
@Mark実際には、sys.exitは通常の例外をスローします。しかし、はい、プロセスをすぐに終了させるものは、他に何も実行しないことを意味します。
アンチモン2012

1
@アンチモン:ありがとう。に変更されましたos._exit
マーク・バイアーズ

ただ疑問に思うのは、例外が見つかった場合にのみコードが入力される場合を除き、クリーンアップコードを内に配置できないのはなぜですか。
スティーブンジェイコブ

2
@Stephen一つには、tryブロックから戻った場合でも、最終的にコードが実行されます。その場合、except句はヒットしません。
アンチモン

18

上記の他の回答に追加すると、例外は発生しなかった場合にのみ句が実行さ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例外に関係なく句が実行されることがわかります。お役に立てれば。


2
OPが違いを知りたいので質問に答えない「finally」節を使用しなかったとしても、これはうまくいきました。良い例は、IOErrorとは異なるエラーを引き起こして、最終的に節ブロックは、例外が呼び出し元に伝達される前に実行されます。
Reda Drissi

2
なんか知らなかったelse。知っておくと便利です。
mazunki

8

コードブロックは同等ではありません。このfinally句は、run_code1()以外の例外をスローした場合TypeError、またはrun_code2()例外をスローしたother_code()場合にも実行されますが、最初のバージョンではこれらの場合は実行されません。


7

最初の例でrun_code1()は、そうでない例外が発生するとどうなりTypeErrorますか?... other_code()は実行されません。

それをfinally:バージョンと比較してください:other_code()発生した例外に関係なく実行されることが保証されています。


7

ドキュメントで説明されているように、このfinally句は、あらゆる状況で実行する必要があるクリーンアップアクションを定義することを目的としています。

存在する場合finallyは、「クリーンアップ」ハンドラを指定します。try 句は、いずれかを含む、実行されるexceptelse句。いずれかの句で例外が発生して処理されない場合、例外は一時的に保存されます。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句はどのイベントでも実行されます。TypeError2つの文字列を分割することにより上昇はによって処理されていないexcept後句したがって再上昇finally句が実行されました。

実際のアプリケーションでは、finally節は、リソースの使用が成功したかどうかに関係なく、外部リソース(ファイルやネットワーク接続など)を解放するのに役立ちます。


4

完璧な例は以下の通りです:

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)

3

finally「クリーンアップアクション」を定義するためのものです。finally句は、出発前に任意のイベントで実行されるtry例外は(あなたがそれを処理しない場合でも)発生しているか否か、文を。

@Byersの例の2番目です。


2

最後に、メイン作業のコードを実行する前に「オプション」コードを実行する場合にも使用できます。そのオプションコードはさまざまな理由で失敗する可能性があります。

次の例では、どのような例外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()     

上記のコードは、コードの最初のブロックと同じ効果がありますが、より簡潔です。


2

Delphiを数年間専門的に使用することで、最終的に使用するクリーンアップルーチンを保護するように教えられました。Delphiは、メモリリークが発生しないように、tryブロックの前に作成されたリソースをクリーンアップするために、finallyの使用をほぼ強制します。これは、Java、Python、Rubyの動作方法でもあります。

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

そして、リソースは試行してから最終的に何をするかに関係なくクリーンアップされます。また、実行がtryブロックに到達しない場合は、クリーンアップされません。(つまり、create_resourceそれ自体が例外をスローします)コードを「例外的に安全」にします。

実際にfinallyブロックが必要な理由については、すべての言語で必要なわけではありません。例外がスタックをアンロールするときにクリーンアップを強制するデストラクターを自動的に呼び出したC ++。これは、最終的に言語を試してみるよりも、よりクリーンなコードの方向へのステップアップだと思います。

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.

2

tryブロックには、必須の句が1つだけあります。それは、tryステートメントです。except、else、finally句はオプションであり、ユーザー設定に基づきます。

finally:Pythonがtryステートメントを終了する前に、プログラムを終了する場合でも、あらゆる条件下でfinallyブロックのコードを実行します。たとえば、exceptまたはelseブロックでコードを実行中にPythonがエラーに遭遇した場合、プログラムを停止する前に、finallyブロックが引き続き実行されます。


1
これは間違っています。exceptステートメントは必須です。– Lucas Azevedo 2月1日12:04 これは誤りです。「except」句のない、try-finallyブロックを含むPython 3.5プログラムをコンパイルして実行したところです。
Rob Tow

2
私はこれを自分で試しましたが、信じられないことに、except句は必須ではありません。
captainblack

1

これらのPython3コードを実行して、finallyの必要性を監視します。

ケース1:

count = 0
while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")
        finally:
            print("Your Attempts: {}".format(count))

ケース2:

count = 0

while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")

        print("Your Attempts: {}".format(count))

毎回次の入力を試してください。

  1. ランダム整数
  2. 586である正しいコード(これを試してください、あなたはあなたの答えを得るでしょう)
  3. ランダムな文字列

** Pythonの学習のごく初期の段階。


1

Excelシートを読みたいコードを実行しようとしました。sayという名前のシートがないファイルがある場合、問題は次のとおりでした:SheetSumエラーの場所に移動できません!! 私が書いたコードは:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

エラーを与える:

[WinError 32]別のプロセスによって使用されているため、プロセスはファイルにアクセスできません

私は完全なtry except with finallyブロックを追加finallyし、次のような場合にはファイルを閉じる必要があることを伝える必要がありました。

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets_file = open(data_file,'rb')
        sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    finally:
        sheets_file.close()
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

それ以外の場合、ファイルはまだ開いたままで、背景です。

存在する場合finallyは、クリーンアップハンドラーを指定します。try 句は、いずれかを含む、実行されるexceptelse句。いずれかの句で例外が発生して処理されない場合、 例外は一時的に保存されます。finally節が実行されます。保存された例外がある場合、それはfinally 条項の終わりに再度発生します。場合finally句は別の例外を発生させ、保存された例外は新しい例外のコンテキストとして設定されています。

..もっとここに

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.