Stack Overflow の他の質問で、 の使用はexcept: pass
推奨されていないというコメントをよく見かけます。これはなぜ悪いのでしょうか? エラーが何であるかは気にせず、コードをそのまま続行したい場合もあります。
try:
something
except:
pass
ブロックの使用はなぜexcept: pass
悪いのでしょうか? 何が悪いのでしょうか?pass
エラーが発生しているからでしょうか、それともexcept
何らかのエラーが発生しているからでしょうか?
ベストアンサー1
ご想像のとおり、これには 2 つの側面があります。の後に例外タイプを指定せずにエラーをexcept
キャッチし、何もアクションを実行せずに単に渡すことです。
私の説明は「少し」長くなりますが、要約すると次のようになります。
- エラーをキャッチしないでください。回復する準備ができている例外を常に指定し、それらの例外のみをキャッチします。
- except ブロックを渡さないようにしてください。明示的に要求されない限り、これは通常、良い兆候ではありません。
しかし、詳細を見ていきましょう。
エラーをキャッチしない
ブロックを使用する場合try
、通常は例外がスローされる可能性があることがわかっているため、これを行います。そのため、何が壊れるか、どのような例外がスローされるかについても、すでに大まかな見当がついています。このような場合、確実に回復できるため、例外をキャッチします。つまり、例外に対する準備ができており、その例外が発生した場合に従う代替プランがあるということです。
例えば、ユーザーに数字を入力するよう求める場合、入力を変換してint()
、ValueError
ユーザーにもう一度試すように求めるだけで簡単に回復できるので、をキャッチしてValueError
ユーザーに再度プロンプトを出すのが適切な計画です。別の例としては、ファイルから何らかの構成を読み取りたいが、そのファイルが存在しない場合があります。これは構成ファイルであるため、フォールバックとしてデフォルトの構成がある可能性があり、ファイルは必ずしも必要ではありません。したがって、をキャッチして、FileNotFoundError
ここでは、単にデフォルト設定を適用するのが適切な計画です。どちらの場合も、非常に具体的な例外が予想され、それを回復するための同様に具体的な計画があります。そのため、それぞれのケースで、except
特定の例外のみを明示的に指定します。
ただし、すべてをキャッチすると、回復できるように準備されている例外に加えて、予期していなかった例外が発生し、実際には回復できない、または回復すべきではない例外が発生する可能性もあります。
上の設定ファイルの例を見てみましょう。ファイルが見つからない場合は、デフォルトの設定を適用し、後で設定を自動的に保存するように決定します(次回はファイルが存在するようになります)。次に、IsADirectoryError
、またはPermissionError
代わりに、実行を継続する必要はありません。デフォルトの構成を適用することはできますが、後でファイルを保存できなくなります。また、ユーザーはカスタム構成を使用するつもりだった可能性が高いため、デフォルト値の使用は望ましくありません。そのため、ユーザーにすぐに通知し、プログラムの実行も中止する必要があります。ただし、これは小さなコード部分の奥深くで行うべきことではありません。これはアプリケーション レベルで重要なことなので、上部で処理する必要があります。つまり、例外が浮上するようにしてください。
もう一つの簡単な例もPython 2 のイディオムドキュメント。ここでは、コードに単純なタイプミスがあり、それがエラーの原因となっています。すべての例外をキャッチしているので、NameError
sそしてSyntaxError
sどちらもプログラミング中に誰もが経験するミスであり、コードを出荷するときには絶対に含めたくないミスです。しかし、これらも検出したため、そこでミスが発生したことすらわからず、正しくデバッグするための助けが失われます。
しかし、私たちが想定していない、より危険な例外もあります。例えば、システムエラーこれは通常、めったに起こらず、実際に計画することができない何かです。つまり、より複雑な何かが起こっており、現在のタスクの続行を妨げる可能性が高いことを意味します。
いずれにせよ、コードの小規模な部分ですべてに備えることはほとんど不可能なので、その部分では、準備している例外だけをキャッチするべきです。少なくとも、Exception
や などは含まれないためSystemExit
、アプリケーションを終了するKeyboardInterrupt
ように設計されていますが、それでもまだあまりに漠然としていると思います。個人的に例外のキャッチException
や例外そのものを受け入れる場所は 1 つだけあり、それは、予期しない例外をログに記録することを唯一の目的とする単一のグローバル アプリケーション レベル例外ハンドラーです。この方法であれば、予期しない例外に関する情報をできるだけ多く保持できるため、その情報を使用してコードを拡張し、それらの例外を明示的に処理したり (回復できる場合)、バグの場合はテスト ケースを作成して再発しないようにすることができます。ただし、もちろん、これは予期していた例外のみをキャッチした場合にのみ機能するため、予期していなかった例外は自然に浮上します。
exceptブロックを渡さないようにしてください
特定の例外を明示的にキャッチする場合、何もしなくても問題ない状況が多くあります。そのような場合は、単に持っているだけで十分です。except SomeSpecificException: pass
ただし、ほとんどの場合、回復プロセスに関連するコードが必要になる可能性が高いため、これは当てはまりません (前述のとおり)。たとえば、アクションを再試行したり、代わりにデフォルト値を設定したりすることができます。
ただし、そうでない場合、たとえば、コードが既に成功するまで繰り返すように構成されている場合は、単に渡すだけで十分です。上記の例で言えば、ユーザーに数字を入力するように依頼したい場合があります。ユーザーは要求されたことを実行したくないことがわかっているので、最初からループに入れておくと、次のようになります。
def askForNumber ():
while True:
try:
return int(input('Please enter a number: '))
except ValueError:
pass
例外がスローされなくなるまで試行を続けるため、except ブロックで特別な操作を行う必要はなく、これで問題ありません。ただし、少なくともユーザーにエラー メッセージを表示して、なぜ入力を繰り返さなければならないのかを伝えたいと考える人もいるでしょう。
ただし、他の多くの場合、 を渡すだけでは、except
キャッチする例外に対して十分な準備ができていないことを示しています。 それらの例外が単純 ( や などValueError
)TypeError
で、渡すことができる理由が明白でない限り、単に渡すことは避けてください。 本当に何もする必要がない場合 (そして、それが絶対に確実である場合) は、その理由をコメントで追加することを検討してください。 そうでない場合は、 except ブロックを拡張して、実際に回復コードを含めます。
except: pass
しかし、最もひどいのは、この 2 つを組み合わせた場合です。つまり、まったく準備ができていないにもかかわらず、意図的にエラーをキャッチし、それに対して何もしないということです。少なくともエラーをログに記録し、おそらくエラーを再発生させてアプリケーションを終了する必要があります (MemoryError の後、通常どおりに続行できる可能性は低いです)。単にエラーをそのまま通過させると、アプリケーションがある程度存続するだけでなく (もちろん、どこでキャッチするかによって異なります)、すべての情報が破棄され、エラーを発見できなくなります。これは、エラーを発見したのが自分ではない場合に特に当てはまります。
つまり、結論は次のようになります。本当に予想され、回復する準備ができている例外のみをキャッチします。他の例外は、修正する必要がある間違いか、いずれにしても準備ができていないもののいずれかである可能性があります。特定の例外を渡すことは、それらについて何かをする必要がない場合は問題ありません。それ以外の場合は、それは単なる思い込みと怠惰の兆候です。そして、あなたは間違いなくそれを修正する必要があります。