web-dev-qa-db-ja.com

「except」ステートメントで例外タイプを常に指定する必要がありますか?

PyCharm IDEを使用する場合、例外タイプなしでexcept:を使用すると、この例外句がToo broadであることをIDEから思い出させます。

このアドバイスを無視すべきですか?それとも、例外タイプを常に特定するのはPythonicですか?

81
HorseloverFat

ほとんどの場合、明示的な例外タイプを指定することをお勧めします。裸のexcept:句を使用すると、キャッチするはずの例外以外の例外をキャッチしてしまう可能性があります。これにより、バグを隠したり、プログラムが期待どおりに動作していないときにプログラムをデバッグしにくくなったりする可能性があります。

たとえば、データベースに行を挿入する場合、その行が既に存在することを示す例外をキャッチして、更新を行うことができます。

try:
    insert(connection, data)
except:
    update(connection, data)

裸のexcept:を指定すると、データベースサーバーが転倒したことを示すソケットエラーもキャッチします。処理方法がわかっている例外のみをキャッチするのが最善です。多くの場合、例外のポイントでプログラムが失敗するのは、続行するよりも奇妙な予期しない方法で動作するよりも優れています。

裸のexcept:を使用する場合の1つのケースは、ネットワークサーバーのように、常に実行する必要があるプログラムの最上位レベルです。しかし、その後、例外をログに記録するように非常に注意する必要があります。基本的に、これを行うプログラム内の場所は1つだけである必要があります。

これのすべての結果は、コードがexcept:(またはalmostと同じexcept Exception:)を使用するように強制するため、コードがraise Exception('some message')を実行しないことです。 。通知する問題に固有の例外を定義する必要があります(ValueErrorTypeErrorなどの組み込み例外サブクラスから継承する場合があります)。または、特定の組み込み例外を発生させる必要があります。これにより、コードのユーザーは、処理したい例外だけをキャッチするように注意することができます。

76
babbageclunk

通訳者からのアドバイスを無視してはいけません。

PEP-8 Pythonのスタイルガイドから:

例外をキャッチする場合は、裸のexcept:句を使用する代わりに、可能な限り特定の例外に言及してください。

たとえば、次を使用します。

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

裸のexcept:句はSystemExitおよびKeyboardInterrupt例外をキャッチし、Control-Cでプログラムを中断することを難しくし、他の問題を隠すことができます。プログラムエラーを通知するすべての例外をキャッチする場合は、Exception:以外を使用します(bare exceptはBaseException:以外と同等です)。

経験則として、裸の「except」句の使用を2つのケースに制限することをお勧めします。

例外ハンドラーがトレースバックを出力または記録する場合;少なくともユーザーはエラーが発生したことを認識します。コードでクリーンアップ作業を行う必要があるが、raiseを使用して例外を上方に伝播させる場合。 try ... finallyは、このケースを処理するためのより良い方法です。

34
asheeshr

Pythonこれに特化したものではありません。

例外の全体的なポイントは、問題が発生した場所にできるだけ近い場所で問題を処理することです。

そのため、例外的な状況で問題を引き起こす可能性のあるコードと、解決策が互いに「隣接」してしまう可能性があります。

問題は、コードによってスローされる可能性のあるすべての例外を知ることができないことです。あなたが知ることができるのは、それがファイルが見つからないという例外である場合、それをトラップし、ユーザーにその機能を実行またはキャンセルするものを取得するよう促すことができるということです。

キャッチしてみると、ファイルルーチンに問題があったとしても(読み取り専用、アクセス許可、UAC、実際にはpdfなどではありません)、すべてがキャッチされていないファイルにドロップされ、ユーザーは「しかしそこにある、このコードはくだらない」と叫んでいる

今、あなたはすべてを捕まえるかもしれない状況がいくつかありますが、それらは意識的に選択されるべきです。

これらはキャッチされ、ローカルアクション(リソースの作成やロックなど)を取り消します(たとえば、ディスク上のファイルを開いて書き込むなど)。その後、例外を再度スローし、より高いレベルで処理します。

他のあなたはあなたがそれが間違った理由を気にしません。たとえば印刷。あなたは、あなたのプリンタに何らかの問題があると言って、それを整理してください、そしてそれのためにアプリケーションを殺さないで、すべてのラウンドを持っているかもしれません。コードが何らかの種類のスケジュールを使用して一連の個別のタスクを実行した場合、同様の無駄になりますが、タスクの1つが失敗したため、全体を停止する必要はありません。

注:上記を行う場合、例外ログのようなものはお勧めできません。十分にログの終わりをキャッチしてみてください。

8
Tony Hopkinson

また、キャッチします。 Control-Cを使用しているので、もう一度「投げる」場合を除き、実行しないでください。ただし、その場合は「最終的に」使用する必要があります。

3
Ulrich Eckhardt

ここに私が使用する場所があります

  1. 迅速で汚いプロトタイピング

それは私のコードで未チェックの例外の主な用途です

  1. トップレベルのmain()関数。キャッチされないすべての例外を記録します。

私は常にこれを追加するので、実動コードがスタックトレースをこぼさないようにします

  1. アプリケーション層間

私はそれを行う2つの方法があります:

  • 最初の方法:上位層が下位関数を呼び出すと、「トップ」の下位例外を処理するために、型付き例外で呼び出しをラップします。しかし、低レベル関数で未処理の低レベル例外を検出するために、一般的な例外ステートメントを追加します。

私はこの方法を好む、どの例外が適切にキャッチされるべきかを検出するのが簡単だと思う:私はより低いレベルの例外がより高いレベルで記録されるとき問題をよりよく「見る」

  • 2番目の方法:下位層の各最上位関数は、その特定の層で未処理の例外をすべてキャッチすることを除いて、コードをジェネリックにラップします。

一部の同僚は、この方法を好んでいます。下位レベルの関数では、それらが「所属」しているため、下位レベルの例外を保持しているためです。

3
nipil

例外の種類を常に指定してください。SyntaxErrorKeyboardInterruptMemoryErrorなど、キャッチしたくない種類がたくさんあります。

3
Pavel Anossov