150

if何かが有効であるかどうかをテストする必要がありますか、それとも単にtryそれを実行して例外をキャッチする必要がありますか?

  • 1つの方法が好ましいと言っている確かな文書はありますか?
  • 片方はもっとpythonicですか?

たとえば、次のようにする必要があります。

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'

または:

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'

いくつかの考え...
PEP20は言う:

エラーが黙って通過することはありません。
明示的に沈黙させない限り。

tryの代わりに使用することは、ifサイレントパスのエラーとして解釈されるべきですか?もしそうなら、あなたはそれをこのように使用することによってそれを明示的に沈黙させているので、それを大丈夫にしますか?


私はあなたが物事を一方向にしかできない状況について言及していません。例えば:

try:
    import foo
except ImportError:
    import baz
4

8 に答える 8

170

その結果が生じる場合は、より優先try/exceptする必要がありますif/else

  • スピードアップ(たとえば、余分なルックアップを防ぐことによる)
  • よりクリーンなコード(行数が少ない/読みやすい)

多くの場合、これらは密接に関連しています。


スピードアップ

長いリストから要素を見つけようとする場合:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

indexがおそらくリストにあり、IndexErrorが通常発生しない場合を除いて、tryは最良のオプションです。このようにして、による追加のルックアップの必要性を回避しますif index < len(my_list)

Pythonは、 DiveIntoPythonのフレーズである例外の使用を推奨しています。あなたの例は、例外を(優雅に)処理するだけでなく、サイレントに通過させるのではなく、インデックスが見つからないという例外的な場合にのみ例外が発生します(したがって、例外という言葉があります!)。


よりクリーンなコード

公式のPythonドキュメントには、EAFPが記載されています。許可よりも許しを求めるのが簡単です。RobKnightエラーを回避するのではなくキャッチすると、コードがよりクリーンで読みやすくなる可能性があると述べています。彼の例では、次のように述べています。

さらに悪い(LBYL'飛躍する前に見てください')

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

より良い(EAFP:許可よりも許しを求める方が簡単)

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None
于 2011-09-30T00:09:27.137 に答える
21

この特定のケースでは、他のものを完全に使用する必要があります。

x = myDict.get("ABC", "NO_ABC")

ただし、一般的には、次のようになります。テストが頻繁に失敗することが予想される場合は、を使用しますif。操作を試行し、失敗した場合に例外をキャッチするだけの場合に比べてテストに費用がかかる場合は、を使用しますtry。これらの条件のいずれにも当てはまらない場合は、読みやすいものを使用してください。

于 2011-09-29T23:59:32.803 に答える
9

競合状態の可能性がある場合はガード内ではなく直接使用する必要がtryあります。たとえば、ディレクトリが存在することを確認する場合は、次のことを行わないでください。exceptif

import os, sys
if not os.path.isdir('foo'):
  try:
    os.mkdir('foo')
  except OSError, e
    print e
    sys.exit(1)

別のスレッドまたはプロセスがとの間にディレクトリを作成したisdir場合mkdirは、終了します。代わりに、これを行います。

import os, sys, errno
try:
  os.mkdir('foo')
except OSError, e
  if e.errno != errno.EEXIST:
    print e
    sys.exit(1)

'foo'ディレクトリを作成できない場合にのみ終了します。

于 2015-09-22T20:14:18.820 に答える
8

あなたがそれをする前に何かが失敗するかどうかをチェックするのが簡単であるならば、あなたはおそらくそれを支持するべきです。結局のところ、例外(関連するトレースバックを含む)の作成には時間がかかります。

例外は次の場合に使用する必要があります。

  1. 予期しないこと、または...
  2. 複数のレベルのロジックをジャンプする必要がある場合(たとえば、breakが十分に遠くまで到達できない場合)、または...
  3. 何が例外を事前に処理するのか正確にわからない場合、または...
  4. 事前に障害をチェックするのに費用がかかるもの(単に操作を試みる場合に比べて)

多くの場合、本当の答えは「どちらでもない」であることに注意してください。たとえば、最初の例では、実際に行うべき.get()ことは、デフォルトを提供するために使用することです。

x = myDict.get('ABC', 'NO_ABC')
于 2011-09-29T23:59:09.693 に答える
6

他の投稿が述べているように、それは状況に依存します。特に大規模なプロジェクトでデータを使用する場合は、データの有効性を事前にチェックする代わりにtry/exceptを使用することにはいくつかの危険があります。

  • tryブロックのコードは、例外がキャッチされる前にあらゆる種類の大混乱を引き起こす可能性があります。事前にifステートメントで事前に確認すれば、これを回避できます。
  • tryブロックで呼び出されたコードが、TypeErrorやValueErrorなどの一般的な例外タイプを発生させる場合、実際には、キャッチすることを期待していたのと同じ例外をキャッチしない可能性があります。例外が発生する可能性のある行。

たとえば、次のようになっているとします。

try:
    x = my_list[index_list[3]]
except IndexError:
    x = 'NO_ABC'

IndexErrorは、index_listまたはmy_listの要素を取得しようとしたときに発生したかどうかについては何も示していません。

于 2014-10-16T17:03:10.060 に答える
4

ifの代わりにtryを使用して、サイレントパスのエラーとして解釈する必要がありますか?もしそうなら、あなたはそれをこのように使用することによってそれを明示的に沈黙させているので、それを大丈夫にしますか?

を使用tryすると、エラーが通過する可能性があることを認識します。これは、エラーをサイレントに通過させるのとは逆です。使用するexceptと、まったく通過しなくなります。

ロジックがより複雑なtry: except:場合は、を使用することをお勧めします。if: else:単純な方が複雑な方が優れています。複雑なものは複雑なものよりも優れています。許可よりも許しを求める方が簡単です。

「エラーが黙って渡されてはならない」というのは、コードがあなたが知っている例外を発生させる可能性があり、設計がその可能性を認めているが、例外に対処する方法で設計していない場合です。私の見解では、エラーを明示的にサイレンシングすることpassは、exceptブロック内のようなことを行うことです。これは、「何もしない」ことが特定の状況での正しいエラー処理であるという理解の下でのみ実行する必要があります。(これは、適切に記述されたコードでのコメントがおそらく本当に必要であると私が感じる数少ない時間の1つです。)

ただし、特定の例では、どちらも適切ではありません。

x = myDict.get('ABC', 'NO_ABC')

一般的に理解したいという願望を認め、より良い例を思い付くことができないにもかかわらず、誰もがこれを指摘している理由は、同等のサイドステップが実際にかなりの数の場合に存在し、それらを探すことが問題を解決するための最初のステップ。

于 2011-09-30T00:07:08.320 に答える
3

制御フローに使用するときはいつでもtry/except、自問してください。

  1. tryブロックが成功したときと失敗したときを簡単に確認できますか?
  2. ブロック内のすべての副作用に気づいていますか?try
  3. ブロックが例外をスローするすべてのケースを知っていますか?try
  4. ブロックの実装がtry変更された場合でも、制御フローは期待どおりに動作しますか?

これらの質問の1つまたは複数に対する答えが「いいえ」である場合、多くの許しを求めることができるかもしれません。おそらくあなたの将来の自己から。


例。私は最近、次のような大きなプロジェクトのコードを見ました。

try:
    y = foo(x)
except ProgrammingError:
    y = bar(x)

プログラマーと話すと、意図した制御フローは次のようになりました。

xが整数の場合、y = foo(x)を実行します。

xが整数のリストである場合、y = bar(x)を実行します。

これが機能したfooのは、データベースクエリを作成し、xが整数の場合はクエリが成功し、がリストのProgrammingError場合はクエリが成功するためです。x

ここで使用try/exceptすることは悪い選択です:

  1. 例外の名前である、ProgrammingErrorは、実際の問題(x整数ではない)を示していないため、何が起こっているのかを確認するのが困難です。
  2. ProgrammingErrorデータベース呼び出し中に発生するため、時間が無駄になります。foo例外をスローする前にデータベースに何かを書き込んだり、他のシステムの状態を変更したりすると、事態は本当に恐ろしいものになります。
  3. が整数のリストである場合ProgrammingErrorにのみ発生するかどうかは不明です。xたとえば、fooのデータベースクエリにタイプミスがあるとします。これにより、が発生する場合もありProgrammingErrorます。その結果、が整数のbar(x)場合にも呼び出されるようになりました。xこれにより、不可解な例外が発生したり、予期しない結果が発生したりする可能性があります。
  4. このtry/exceptブロックは、の将来のすべての実装に要件を追加しますfoo。を変更するときはいつでもfoo、リストをどのように処理するかを考え、エラーが発生しProgrammingErrorないこと、たとえばAttributeErrorエラーが発生しないことを確認する必要があります。
于 2018-08-25T07:10:10.270 に答える
0

一般的な意味については、Pythonでイディオムとアンチイディオムを読むことを検討してください:例外。

あなたの特定のケースでは、他の人が述べたように、あなたは以下を使うべきですdict.get()

get(key [、default])

キーがディクショナリにある場合はキーの値を返し、そうでない場合はデフォルトを返します。defaultが指定されていない場合、デフォルトでNoneに設定されるため、このメソッドでKeyErrorが発生することはありません。

于 2011-09-30T00:09:48.763 に答える