1. ホーム
  2. パイソン

[解決済み】Pythonでtry-except-elseを使用するのは良い習慣ですか?

2022-05-13 09:15:44

質問

Pythonで時々、ブロックを見かけます。

try:
   try_this(whatever)
except SomeException as exception:
   #Handle exception
else:
   return something

try-except-elseが存在する理由は何ですか?

例外を使ってフロー制御を行うような、そういうプログラミングは好きではありません。しかし、言語に含まれているということは、それなりの理由があるのではないでしょうか?

例外はエラーではないというのが私の理解です そして、例外的な状況(例えば、ファイルをディスクに書き込もうとしたら、もう容量がないとか、権限がないとか)にのみ使用されるべきで、フロー制御には使用されないということです。

通常、私は例外を次のように処理します。

something = some_default_value
try:
    something = try_this(whatever)
except SomeException as exception:
    #Handle exception
finally:
    return something

あるいは、どうしても例外が起きても何も返したくないのであれば

try:
    something = try_this(whatever)
    return something
except SomeException as exception:
    #Handle exception

解決方法は?

<ブロッククオート

無知からくるものなのかわかりませんが、私はそのようなことは好きではありません。 例外を使ってフロー制御を行うようなプログラミングです。

Pythonの世界では、フロー制御に例外を使うことは一般的であり、普通のことです。

Pythonのコア開発者でさえ、フロー制御に例外を使っていますし、そのスタイルは言語に大きく食い込んでいます(例えば、イテレータプロトコルで ストップイテレーション を使用してループの終了を通知します)。

さらに、try-except スタイルを使用することで、いくつかの "look-before-you-leap" の構文があります。例えば os.path.exists の場合、使用する頃には古い情報になっている可能性があります。 同様に キュー.フル は、古くなっている可能性のある情報を返します。 その try-except-else スタイル は、このような場合、より信頼性の高いコードを生成します。

<ブロッククオート

例外はエラーではなく、あくまで例外であるというのが私の理解です。 例外的な状況に使用されます。

他の言語では、このルールはライブラリの文化的規範を反映しているものもあります。また、このルールは、それらの言語におけるパフォーマンスへの配慮に部分的に基づいています。

Pythonの文化的規範はやや異なっています。多くの場合、あなたは しなければならない 制御フローに例外を使用します。また、Pythonで例外を使っても、いくつかのコンパイル言語のように周囲のコードや呼び出し元のコードが遅くなることはありません(例. CPython は、実際に例外を使うかどうかにかかわらず、すべてのステップで例外チェックのためのコードをすでに実装しています)。

言い換えれば、「例外は例外のためにある」というあなたの理解は、他の言語では意味をなすルールですが、Pythonでは意味をなしません。

<ブロッククオート

しかし、言語そのものに含まれているのであれば、何か理由があるのでしょう。 それなりの理由があるのですね"。

例外は、競合状態を回避するのに役立つだけでなく、エラー処理をループの外側に引き出すのに非常に便利です。これは、自動的なエラー処理機能を持たないインタプリタ型言語では必要な最適化です。 ループ不変のコード運動 .

また、問題を処理する能力が、問題が発生した場所から遠く離れているような一般的な状況では、例外によってコードをかなり単純化することができます。例えば、トップレベルのユーザーインターフェイスコードがビジネスロジックのコードを呼び出し、それが低レベルルーチンを呼び出すというのはよくあることです。低レベルルーチンで発生した状況(データベースアクセスにおけるユニークキーに対する重複レコードなど)は、トップレベルのコードでしか処理できません(既存のキーと競合しない新しいキーをユーザーに要求するなど)。 このような制御フローに例外を使用することで、中間レベルのルーチンはこの問題を完全に無視し、フロー制御のその側面からうまく切り離すことができるのです。

があります。 例外の必要性について書かれたブログ記事はこちらです。 .

また、Stack Overflowの回答もご覧ください。 例外は本当に例外的なエラーのためにあるのですか?

<ブロッククオート

"try-except-elseが存在する理由は何でしょうか。

else節そのものが面白いですね。例外がないときに実行され、finally-clauseの前に実行されるのです。それが主な目的だ。

else-clauseがなければ、finalizationの前に追加のコードを実行する唯一の選択肢は、try-clauseにコードを追加するという不器用な方法となる。これは不器用なことで、以下のようなリスクがある。 トライブロックによって保護されることを意図していないコードで例外を発生させる。

ファイナライズの前に保護されていないコードを追加で実行するというユースケースは、あまり発生しません。ですから、公開されているコードで多くの例を見ることは期待しないでください。やや稀なケースです。

else句のもう一つの使用例は、例外が発生しないときに必ず発生し、例外が処理されたときには発生しない動作を実行することである。例えば

recip = float('Inf')
try:
    recip = 1 / f(x)
except ZeroDivisionError:
    logging.info('Infinite result')
else:
    logging.info('Finite result')

もう一つの例は、unittestのランナーで発生します。

try:
    tests_run += 1
    run_testcase(case)
except Exception:
    tests_failed += 1
    logging.exception('Failing test case: %r', case)
    print('F', end='')
else:
    logging.info('Successful test case: %r', case)
    print('.', end='')

最後に、try-blockのelse-clauseの最も一般的な使い方は、ちょっとした美化(例外的な結果と例外的でない結果を同じインデントレベルで揃えること)である。この使用は常に任意であり、厳密には必要ありません。