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


93

PyCharm IDEを使用する場合except:、例外タイプなしでを使用すると、この例外句であるというIDEからの通知がトリガーされますToo broad

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


答えよりもこれについて詳しく知りたい場合は、Googleの例外を飲み込んでください。あなたは他のあらゆる種類の面白いことをすることができ、それらと一緒にしてはいけません。コードのにおいは別のものです。
トニーホプキンソン2013

回答:


89

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

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

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

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

ベアを使用したい場合の1つexcept:は、ネットワークサーバーのように、常に実行している必要があるプログラムの最上位レベルです。ただし、その場合は例外をログに記録するように細心の注意を払う必要があります。そうしないと、問題の原因を突き止めることができなくなります。基本的に、これを行うプログラム内の場所は1つだけです。

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


7
+1非常に正しい。この例ではさらに楽しいです:(except:他の多くのものの中で)NameErrorをキャッチAttributeErrorし、tryブロックのスペルを間違えた場合(たとえば、insert_one誰かが必要以上に一貫性を評価しなかったために「挿入」関数が実際に呼び出された場合)、常に静かにしようとしupdate()ます。

1
では、現在の呼び出しサイトの上に例外がスローされないようにする必要がある場合はどうでしょうか。つまり、スローされると予測できる特定の例外をすべてキャッチしました。ここで、「実行していない実行コンテキストを強制終了する前にログに記録する必要がある」と追加する必要があります。main())?
アダムパーキン

それは、私が「1つのケース...」で始まる段落で話しているような状況です。それは時々絶対に必要ですが、与えられたプログラムはそれを行う場所を1つだけ持つべきです。また、何が起こっているのかをログで明らかにするように注意する必要があります。そうしないと、プログラムがイベント/要求/何を正しく処理していないのかを解決しようとする苛立たしい時間がかかります。
babbageclunk 2015年

3
@delnan:それより悪い。except Exception:キャッチしますNameErrorAttributeError、あまりにも。むずかしいのexcept:は、ビジネスがキャッチされていないものをキャッチすることです。たとえば、SystemExitexitまたはを呼び出すsys.exitと発生し、意図したexitが阻止されます)、KeyboardInterrupt(ここでも、ユーザーがCtrl-Cを押した場合、おそらく必要ありません)それらを悪用するだけのために実行し続けるため)。後者だけがキャッチしても意味があり、明示的にキャッチする必要があります。少なくともexcept Exception:これら2つは正常に伝播します。
ShadowRanger、2015

38

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

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

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

たとえば、次のように使用します。

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

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

大まかな経験則として、裸の「except」句の使用を2つのケースに制限します。

例外ハンドラがトレースバックを出力またはログする場合。少なくともユーザーはエラーが発生したことに気づくでしょう。コードでクリーンアップ作業を行う必要があるが、レイズで例外を上方に伝播させる場合。試してみてください...最終的には、このケースを処理するためのより良い方法です。



9

Pythonに固有ではありません。

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

したがって、例外的な状況で問題が発生し、解決策が互いに「隣り合う」可能性があるコードを保持します。

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

あなたがそれを試してみると、ファイルルーチンにどんな問題があったとしても(読み取り専用、権限、UAC、実際にはpdfなどではない)、すべての人があなたのファイルを見つけられませんでした。 「しかし、そこにある、このコードはくだらない」と叫んでいる

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

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

もう1つは、問題が発生した理由を気にしないことです。たとえば印刷。プリンタに問題があります。問題を解決するためにアプリケーションを強制終了しないでください。同様に、コードがなんらかのスケジュールを使用して一連の個別のタスクを実行した場合、タスクの1つが失敗したため、すべてを終了させたくはありません。

注上記を行う場合、ある種の例外ログをお勧めすることはできません。たとえば、catch log endを十分に試してください。


バランスの問題だと思います。例外を回復するには、例外を早期にキャッチする必要があり、例外をどこに進めればよいかを知るのが遅くなる必要があります。そのため、Java例外処理がこのような大混乱を引き起こします。これは、各ステップで例外を再ラップする必要があり、情報が失われるためです。
dhill、2016

2
+1は、「問題が発生した理由を気にしません」。私は、URLから日付/時刻を解析する1行のコードの周りのいくつかの場所でそれを使用しています。サードパーティの日付/時刻解析ライブラリには、スローできる例外がすべてリストされていません(標準のValueErrorに加えて、OverflowErrorとTypeErrorが見つかりましたが、おそらくそれ以上あります)。例外がスローされたので、日付/時刻に問題があることをユーザーに通知する適切なエラーメッセージを提供したいだけです。
Michael Rodby

3

また、たとえばControl-Cをキャッチすることになるので、もう一度「スロー」しない限り、それを行わないでください。ただし、その場合は「最終的に」を使用する必要があります。


3

常にあなたのような、キャッチしたくない多くの種類があり、例外の型を指定しSyntaxErrorKeyboardInterruptMemoryErrorなど


2
使用しexcept Exception:たくない上記のタイプを使用しないでください?
HorseloverFat 2013

except Exception結構です。
Ulrich Eckhardt 2013

4
@HorseloverFat:except ExceptionキャッチSyntaxErrorMemoryError、それが基本クラスであるため。KeyboardInterruptSystemExit(によって発生sys.exit())はキャッチされません(これらは即時のBaseExceptionサブクラスです)
jfs

それは理想的ではないように聞こえます-より正確に指定する方が良いです。
HorseloverFat

3

タイプなしで使用する場合を除いて、私が使用する場所は次のとおりです

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

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

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

私は常にこれを追加して、量産コードがスタックトレースをこぼさないようにします

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

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

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

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

  • それを行うための2番目の方法:下位レベルのレイヤーの各トップレベル関数は、その特定のレイヤーのすべての未処理の例外をキャッチするために、コードを総称でラップします。

一部の同僚は、「所属」する下位レベルの関数で下位レベルの例外を保持するため、この方法を好みます。


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