の使用except: pass
が推奨されない方法に関する他のスタックオーバーフローの質問に対するコメントをよく見ます。なぜこれが悪いのですか?時々私はただエラーが何であるか気にしないで、コードを続けたいだけです。
try:
something
except:
pass
なぜexcept: pass
ブロックの使用が悪いのですか?何が悪いのですか?それは私ということであるpass
エラーオンまたはIそのexcept
いずれかのエラー?
の使用except: pass
が推奨されない方法に関する他のスタックオーバーフローの質問に対するコメントをよく見ます。なぜこれが悪いのですか?時々私はただエラーが何であるか気にしないで、コードを続けたいだけです。
try:
something
except:
pass
なぜexcept: pass
ブロックの使用が悪いのですか?何が悪いのですか?それは私ということであるpass
エラーオンまたはIそのexcept
いずれかのエラー?
回答:
あなたが正しく推測として、それには2つの側面がありますキャッチすべての後に例外の種類を指定しないことで、エラーをexcept
、単に何のアクションも取らずにそれを渡します。
私の説明は「少し」長くなっています。つまり、tl; drはこれに分解されます。
しかし、詳細に行きましょう:
try
ブロックを使用する場合、例外がスローされる可能性があることを知っているため、通常これを行います。そのため、何が壊れるか、どの例外がスローされるかについてのおおよその考えもすでにわかっています。このような場合、例外から確実に回復できるため、例外をキャッチします。これは、例外の準備ができており、その例外が発生した場合に従うべき代替計画があることを意味します。
たとえば、ユーザーに数値の入力を求める場合、を発生さint()
せる可能性のあるを使用して入力を変換できますValueError
。ユーザーにもう一度試すように要求するだけで簡単に回復できます。そのため、をキャッチしValueError
てユーザーにもう一度プロンプトを出すのが適切な計画です。別の例は、ファイルから構成を読み取りたいが、そのファイルが存在しない場合です。これは構成ファイルであるため、フォールバックとしていくつかのデフォルト構成がある可能性があるため、このファイルは必ずしも必要ではありません。したがって、をキャッチFileNotFoundError
してデフォルトの構成を適用するだけの場合は、ここでの良い計画になります。これらの両方のケースで、予想される非常に具体的な例外があり、それから回復するための同様に具体的な計画があります。したがって、いずれの場合も、except
特定の 例外。
ただし、すべてをキャッチした場合は、回復する準備ができている例外に加えて、予期しない例外が発生し、実際には回復できない可能性もあります。または回復しないでください。
上記の設定ファイルの例を見てみましょう。ファイルが欠落している場合は、デフォルトの構成を適用しただけで、後で構成を自動的に保存するように決定する可能性があります(そのため、次にファイルが存在します)。今、私たちはIsADirectoryError
、またはPermissionError
代わりに。そのような場合、おそらく続行したくありません。デフォルトの構成を適用することはできますが、後でファイルを保存することはできません。また、ユーザーがカスタム構成を意図している可能性もあるので、デフォルト値を使用することはおそらく望ましくありません。したがって、すぐにユーザーに通知し、プログラムの実行も中止する必要があります。しかし、それは、小さなコードパーツの奥深くにしたいことではありません。これはアプリケーションレベルで重要なことなので、上で処理する必要があります。そのため、例外が発生します。
別の簡単な例は、Python 2イディオムドキュメントでも説明されています。ここでは、コードを壊す原因となる単純なタイプミスが存在します。すべての例外をキャッチしているので、NameError
sとSyntaxError
sもキャッチします。どちらもプログラミング中に私たち全員に起こる間違いです。どちらも間違いであり、コードの出荷時に絶対に含めたくないものです。しかし、それらも検出したので、それらがそこに発生したことさえわからず、正しくデバッグするための助けを失います。
しかし、私たちが準備する可能性が低い、より危険な例外もあります。たとえば、SystemErrorは通常、まれにしか発生せず、実際に計画することはできません。それは、より複雑なことが起こっていること、現在のタスクを続行できない可能性があることを意味します。
いずれにせよ、コードの小規模な部分ですべての準備をすることはほとんどありません。そのため、準備する例外だけをキャッチする必要があります。一部の人々は、少なくともキャッチに勧めException
、それはのようなものは含まれませんようSystemExit
およびKeyboardInterrupt
その設計によって、アプリケーションを終了することですが、私はこれはまだあまりにも非特異的であることを主張するだろう。私が個人的にキャッチングを受け入れる場所は1つException
だけです。例外。これは、準備されていない例外をログに記録するという単一の目的を持つ単一のグローバルなアプリケーションレベルの例外ハンドラーにあります。こうすることで、予期しない例外に関する多くの情報を保持して、コードを拡張してそれらを明示的に処理する(それらから回復できる場合)、または(バグの場合)テストケースを作成して確認することができます。それは二度と起こりません。しかしもちろん、これは、私たちがすでに期待していた例外をキャッチした場合にのみ機能するため、予期していなかった例外が自然に発生します。
特定の例外の小さな選択を明示的にキャッチする場合、単に何もしないことで問題がなくなる状況が数多くあります。そのような場合は、持って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
最悪の犯罪者は両方の組み合わせです。我々は喜んでキャッチされていることを、この手段の任意我々は絶対にそれのために準備されていないが、エラーをして、我々はまた、それについて何もしません。あなたは、少なくともエラーを記録したいともおそらくそれはまだアプリケーションを終了するためにリレイズ(それはあなたがMemoryError後に通常のように続けることができそうです)。ただ通過するだけで、アプリケーションがいくらか生きているだけでなく(もちろん、どこでキャッチするかによって異なります)、すべての情報が破棄され、エラーを発見できなくなります。これは、発見した人でない場合は特に当てはまります。
つまり、肝心なのは、本当に期待し、回復する準備ができている例外のみをキャッチすることです。他のすべては、修正する必要がある間違いか、とにかく準備ができていない何かの可能性があります。特定の例外を渡す必要がない場合は、例外を渡しても問題ありません。他のすべての場合では、それは推定と怠惰の兆候にすぎません。そして、あなたは間違いなくそれを修正したいと思います。
except
が、その後raise
、引数なしで呼び出し、例外をバブルアップさせ続け、アプリケーションを終了します。気に入っています:ianbicking.org/blog/2007/09/re-raising-exceptions.html。ブランケットを使用しないという規則の確かな例外のように見えexcept
ます。
raise
。ただし、これは通常、アプリケーション内のいくつかの場所でのみ実行し、例外をログに記録します。
なぜ「except:pass」が不適切なプログラミング手法なのですか?
なぜこれが悪いのですか?
try: something except: pass
これには、すべての可能な例外をキャッチしGeneratorExit
、KeyboardInterrupt
、とSystemExit
-あなたは、おそらくキャッチするつもりはないの例外です。キャッチと同じBaseException
です。
try:
something
except BaseException:
pass
Pythonのすべてのエラーは例外を
except:
発生させるため、を使用すると、多くのプログラミングエラーが実行時の問題のようになり、デバッグプロセスが妨げられる可能性があります。
親例外クラスをキャッチすると、そのすべての子クラスもキャッチされます。処理する準備ができている例外のみをキャッチする方がはるかにエレガントです。
これがPython 3の例外階層です。本当にすべてをキャッチしますか?:
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
この形式の例外処理を使用している場合:
try:
something
except: # don't just do a bare except!
pass
その後something
、Ctrl-Cでブロックを中断することはできません。プログラムは、try
コードブロック内のすべての可能な例外を見落とします。
同じ望ましくない動作をする別の例を次に示します。
except BaseException as e: # don't do this either - same as bare!
logging.info(e)
代わりに、探していることがわかっている特定の例外のみをキャッチするようにしてください。たとえば、コンバージョンで値エラーが発生する可能性があることがわかっている場合:
try:
foo = operation_that_includes_int(foo)
except ValueError as e:
if fatal_condition(): # You can raise the exception if it's bad,
logging.info(e) # but if it's fatal every time,
raise # you probably should just not catch it.
else: # Only catch exceptions you are prepared to handle.
foo = 0 # Here we simply assign foo to 0 and continue.
Webスクレイピングを行っていて、aと言われているためにそれを行っている可能性がありUnicodeError
ますが、最も広い例外キャッチを使用しているため、他の根本的な欠陥がある可能性のあるコードは実行を試み、帯域幅を浪費します、処理時間、機器の摩耗、メモリ不足、ごみデータの収集など。
他の人があなたのコードに依存できるように完了するようにあなたに求めている場合、私はすべてを処理することを強いられていると感じています。しかし、開発中に騒々しく失敗することをいとわない場合は、断続的にしかポップアップしない可能性がある問題を修正する機会がありますが、それは長期的にはコストのかかるバグになります。
より正確なエラー処理により、コードをより堅牢にすることができます。
>>> import this
禅のPython、ティム・ピーターズ
醜いよりも美しい方がいいです。
明示的は暗黙的よりも優れています。
シンプルは複雑よりも優れています。
複雑は複雑よりも優れています。
ネストよりもフラットの方が優れています。
疎は密よりも優れています。
読みやすさが重要です。
特別なケースは、ルールを破るほど特別なものではありません。
実用性は純粋さを上回りますが。
エラーがサイレントに渡ることはありません。
明示的に沈黙させない限り。
あいまいな状況に直面して、推測する誘惑を拒否してください。
それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。
あなたがオランダ人でない限り、その方法は最初は明白ではないかもしれませんが。
今は決してないよりはましです。
多くの場合、右今。
実装の説明が難しい場合は、悪い考えです。
実装が説明しやすい場合は、良いアイデアかもしれません。
名前空間は非常に魅力的なアイデアの1つです。もっと多くのことをしましょう。
だから、これが私の意見です。エラーが見つかった場合は常に、それを処理するために何かを行う必要があります。つまり、ログファイルなどに書き込みます。少なくとも、以前はエラーがあったことが通知されます。
まず、Zen of Pythonの 2つの原則に違反しています。
それが意味することは、意図的にエラーを黙って通過させることです。さらに、except: pass
例外をキャッチするため、イベントが正確にどのエラーが発生したかはわかりません。
第2に、PythonのZenから抽象化して、正気の観点から話そexcept:pass
うとすると、システムを使用しても、知識や制御が得られないことに注意してください。経験則では、エラーが発生した場合は例外を発生させ、適切なアクションを実行します。事前にわからない場合は、これらのアクションをどのようにする必要があるか、少なくともどこかにエラーを記録します(例外を再発生させた方がよいでしょう)。
try:
something
except:
logger.exception('Something happened')
しかし、通常は、例外をキャッチしようとすると、おそらく何か間違っているのです!
except:pass
構築物は、基本的にコードがでカバーしながら、出てくる一切の例外条件を封じますtry:
ブロックが実行されているが。
この悪い習慣を作るのは、それが通常あなたが本当に望んでいることではないということです。多くの場合、沈黙させたい特定の条件が近づいています。except:pass
はあまりにも鈍い楽器です。それは仕事を成し遂げるでしょう、しかしそれはまたあなたがおそらく予想していなかった他のエラー状態を覆い隠しますが、他の何らかの方法で対処したいと思うかもしれません。
これをPythonで特に重要にするのは、この言語のイディオムによって、例外は必ずしもエラーではないということです。もちろん、ほとんどの言語と同じように、この方法でよく使用されます。しかし、特にPythonでは、実際の通常の実行ケースの一部ではない一部のコードタスクからの代替出口パスを実装するためにそれらを時々使用しましたが、それでも時々発生することが知られており、ほとんどの場合で予期されることさえあります。SystemExit
古い例として既に言及されていますが、最近の最も一般的な例はかもしれませんStopIteration
。この方法で例外を使用すると、特にイテレーターとジェネレーターが最初にPythonに導入されたときに多くの論争が発生しましたが、最終的にはそのアイデアが普及しました。
#1の理由はすでに述べられています-予期しないエラーを隠します。
(#2)- 他の人がコードを読んで理解するのを難しくします。ファイルを読み取ろうとしたときにFileNotFoundExceptionをキャッチした場合、別の開発者には、「catch」ブロックにどのような機能が必要かは明らかです。例外を指定しない場合、ブロックが何をすべきかを説明するために追加のコメントが必要です。
(#3)- 遅延プログラミングを示します。一般的なtry / catchを使用している場合、プログラムで発生する可能性のあるランタイムエラーを理解していないか、Pythonで発生する可能性のある例外が不明であることを示しています。特定のエラーをキャッチすると、プログラムとPythonがスローするエラーの範囲の両方を理解していることがわかります。これにより、他の開発者やコードレビューアがあなたの仕事を信頼するようになります。
それで、このコードはどのような出力を生成しますか?
fruits = [ 'apple', 'pear', 'carrot', 'banana' ]
found = False
try:
for i in range(len(fruit)):
if fruits[i] == 'apple':
found = true
except:
pass
if found:
print "Found an apple"
else:
print "No apples in list"
ここで、try
- except
ブロックが複雑なオブジェクト階層への数百行の呼び出しであり、それ自体が大きなプログラムの呼び出しツリーの途中で呼び出されることを想像してください。プログラムがうまくいかない場合、どこから探し始めますか?
一般に、エラー/例外は次の3つのカテゴリのいずれかに分類できます。
致命的:あなたのせいではなく、あなたはそれらを防ぐことはできず、あなたはそれらから回復することはできません。それらを無視して続行しないでください。プログラムを不明な状態のままにしてください。エラーがプログラムを終了させるだけで、あなたにできることは何もありません。
骨の折れる:おそらく、見落とし、バグ、またはプログラミングエラーが原因の、あなた自身の過失。バグを修正する必要があります。繰り返しますが、間違いなく無視して続行しないでください。
外因性:これらのエラーは、ファイルが見つからない、接続が終了したなどの例外的な状況で発生する可能性があります。これらのエラーは明示的に処理する必要があります。
すべての場合except: pass
において、プログラムを不明な状態のままにしておくだけで、より多くの損傷を引き起こす可能性があります。
簡単に言えば、例外またはエラーがスローされた場合、何かが間違っています。それほど問題ではないかもしれませんが、gotoステートメントを使用するためだけにエラーや例外を作成、スロー、およびキャッチすることは良い考えではなく、めったに行われません。99%の確率で、どこかで問題が発生しました。
問題に対処する必要があります。生活の中でのように、プログラミングでも、問題をそのままにして無視しようとすると、問題が何度も自分で解消されるわけではありません。代わりに、彼らは大きくなり、増殖します。問題があなたに成長し、さらに先へ進むのを防ぐには、1)問題を取り除いて後で混乱を解消するか、2)問題を封じ込めて後で混乱を解消します。
例外とエラーを無視してそのままにしておくことは、メモリリーク、未解決のデータベース接続、ファイルのアクセス許可の不要なロックなどを体験するための良い方法です。
まれに、問題が非常に小さく、ささいなものであり、try ... catchブロックが必要なことを除けば、自己完結型であるため、後でクリーンアップする必要がないのです。これらは、このベストプラクティスが必ずしも適用されない唯一の状況です。私の経験では、これは一般に、コードが実行していることは基本的にささいなことであり忘れることができることを意味します。
私の会社では、ほとんどの場合、catchブロックで何かを行うことがルールです。何もしない場合は、常に理由を説明してコメントを付ける必要があります。やるべきことがあるときは、空のcatchブロックをパスしたり残したりしてはいけません。
私の意見では、エラーが表示される理由があります。それは私の音が愚かですが、それはそれがそうである方法です。優れたプログラミングでは、それらを処理する必要がある場合にのみエラーが発生します。また、私が少し前に読んだように、「pass-Statementはコードが後で挿入されることを示すステートメントです」ので、もしあなたが空のexcept-statementを持ちたいなら、そうするのを自由に感じてください、しかし良いプログラムのために一部欠けている。あなたが持っているべきものを処理しないので。表示される例外により、入力データを修正したり、データ構造を変更したりして、これらの例外が再び発生しないようにすることができます(ただし、ほとんどの場合(ネットワーク例外、一般入力例外)例外は、プログラムの次の部分が適切に実行されないことを示しています。たとえば、NetworkExceptionはネットワーク接続の切断を示し、プログラムは次のプログラム手順でデータを送受信できません。
ただし、例外のタイプを区別するため、1つのexecption-blockに対してのみpassブロックを使用することは有効です。したがって、すべてのexception-blockを1つにまとめても、空ではありません。
try:
#code here
except Error1:
#exception handle1
except Error2:
#exception handle2
#and so on
そのように書き換えることができます:
try:
#code here
except BaseException as e:
if isinstance(e, Error1):
#exception handle1
elif isinstance(e, Error2):
#exception handle2
...
else:
raise
そのため、pass-statementsを含む複数のexcept-blockでさえ、コードが生成される可能性があり、その構造は特別なタイプの例外を処理します。
これまでに提起されたすべてのコメントは有効です。可能であれば、無視する例外を正確に指定する必要があります。可能であれば、例外の原因を分析し、無視しようとしたものだけを無視し、残りは無視する必要があります。例外が原因でアプリケーションが「見事にクラッシュ」した場合は、それが原因である可能性があります。問題が発生したことを隠すことよりも、発生したときに予期しないことが発生したことを知ることがはるかに重要だからです。
以上のことを踏まえて、プログラミングの実践を最優先事項としないでください。これは愚かです。ignore-all-exceptionsブロックを実行する時間と場所は常にあります。
ばかばかしい最優先の別の例は、goto
演算子の使用です。私が学校にいたとき、私たちの教授は私にgoto
オペレーターに教えてくれました。xyzは決して使用すべきではなく、便利なシナリオはあり得ないとあなたが言う人々を信じてはいけません。常にあります。
エラーの処理はプログラミングで非常に重要です。何が問題かをユーザーに示す必要があります。ほとんどの場合、エラーを無視できます。これは非常に悪いプログラミング習慣です。
それはまだ言及されていないので、使用するのが良いスタイルcontextlib.suppress
です:
with suppress(FileNotFoundError):
os.remove('somefile.tmp')
提供されている例では、例外が発生しても発生しなくても、プログラムの状態は同じままです。つまり、somefile.tmp
常に存在しなくなります。
logging
モジュールをデバッグレベルで使用して、本番環境でのストリーミングを回避しながら、開発で利用できるようにします。