web-dev-qa-db-ja.com

Python try-else

elseステートメントのオプションのtry節の意図された使用は何ですか?

492
geowa4

elseブロック内のステートメントは、実行がtryの下から外れた場合(例外がなかった場合)に実行されます。正直なところ、私は必要性を見つけたことがない。

ただし、 例外処理 には次のように記載されています。

Else節の使用は、try節に追加されたコードを追加するよりも優れています。これは、try ... exceptステートメントによって保護されているコードによって引き起こされなかった例外を誤って捕捉するのを防ぐためです。

したがって、たとえばIOErrorをスローする可能性があるメソッドがあり、それが発生した例外をキャッチしたいが、最初の操作が成功した場合は他に何かしたいことがあります。don'tその操作からIOErrorをキャッチしたい場合は、次のように記述します。

    try:
        operation_that_can_throw_ioerror()
    except IOError:
        handle_the_exception_somehow()
    else:
         # we don't want to catch the IOError if it's raised
        another_operation_that_can_throw_ioerror()
    finally:
        something_we_always_need_to_do()

operation_that_can_throw_ioerrorの後に単にanother_operation_that_can_throw_ioerror()を置くと、exceptは2番目の呼び出しのエラーをキャッチします。そしてそれをtryブロック全体の後に置くと、それは常に実行され、finallyの後までは実行されません。 elseはあなたが確かめることを可能にします

  1. 2番目の操作は、例外がない場合にのみ実行されます。
  2. finallyブロックの前に実行されます。
  3. それが発生させるどんなIOErrorsもここでつかまえられない
759
Blair Conrad

else - スタイルと読みやすさを使用する理由は1つ大きなあります。例外を引き起こす可能性のあるコードを、それらを処理するコードの近くに置くことをお勧めします。たとえば、これらを比較します。

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

そして

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

2つ目は、exceptが早く戻ることができない場合、または例外を再スローする場合に適しています。可能であれば、私は書いただろう:

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

注:最近投稿された複製 から回答をコピーしたもの なので、この「AskPassword」のものすべて。

86
Izkata

1つの用途:例外を発生させるはずのコードをテストします。

try:
    this_should_raise_TypeError()
except TypeError:
    pass
except:
    assert False, "Raised the wrong exception type"
else:
    assert False, "Didn't raise any exception"

(このコードは実際にはより一般的なテストに抽象化されるべきです。)

45
Darius Bacon

Python try-else

Tryステートメントのオプションのelse節の意図された使用は何ですか?

意図された使用はそれが扱われると予想されるところに例外がなかったなら実行するためにもっと多くのコードのための文脈を持つことです。

このコンテキストは、予期していなかったエラーを誤って処理しないようにします。

returncontinue、およびbreakは、elseへの制御フローを中断する可能性があるため、else節が実行される正確な条件を理解することが重要です。

要約すれば

elseステートメントは、noの例外がなく、returncontinue、またはbreakステートメントによって割り込まれない場合に実行されます。

他の答えはその最後の部分を逃します。

ドキュメントより:

オプションのelse句は、controltry句の末尾から離れたときに実行されます。

(太字は付け加えた。)そして脚注はこう読みます:

*現在のところ、例外またはreturncontinue、またはbreakステートメントの実行を除いて、制御は「終わりから流れています」。

少なくとも1つの先行するexcept節を必要とします( 文法を参照してください )。したがって、それは実際には「try-else」ではなく、「try-except-else(-finally)」であり、else(およびfinally)はオプションです。

Pythonチュートリアル では、使用目的について詳しく説明しています。

Try ... exceptステートメントには、オプションのelse節があります。これが存在する場合は、except節をすべて続ける必要があります。 try句が例外を発生させない場合に実行されなければならないコードに役立ちます。例えば:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Else節の使用は、try節に追加されたコードを追加するよりも優れています。これは、try ... exceptステートメントによって保護されているコードによって引き起こされなかった例外を誤って捕捉するのを防ぐためです。

elseブロックに続くコードとtryを区別する例

エラーを処理した場合、elseブロックは実行されません。例えば:

def handle_error():
    try:
        raise RuntimeError('oops!')
    except RuntimeError as error:
        print('handled a RuntimeError, no big deal.')
    else:
        print('if this prints, we had no error!') # won't print!
    print('And now we have left the try block!')  # will print!

そしていま、

>>> handle_error()
handled a RuntimeError, no big deal.
And now we have left the try block!
36
Aaron Hall

Try-except-elseは、 EAFPパターンduck-typing を組み合わせるのに最適です。

try:
  cs = x.cleanupSet
except AttributeError:
  pass
else:
  for v in cs:
    v.cleanup()

この素朴なコードで問題ないと思うかもしれません。

try:
  for v in x.cleanupSet:
    v.clenaup()
except AttributeError:
  pass

これは、コード内の誤った重大なバグを隠すのに最適な方法です。私はそこでクリーンアップをタイプミスしました、しかし私に知らせるであろうAttributeErrorは飲み込まれています。さらに悪いことに、それを正しく書いたとしたら、クリーンアップ・メソッドが誤った属性を持つユーザー・タイプを渡されることがあり、途中で静かに失敗してファイルをクローズしないままにしていました。幸運にもそれをデバッグすること。

17
Alice Purcell

たとえ例外があったとしてもそれをしなければならないクリーンアップがあるとき、私はそれが本当に役に立つと思います:

try:
    data = something_that_can_go_wrong()
except Exception as e: # yes, I know that's a bad way to do it...
    handle_exception(e)
else:
    do_stuff(data)
finally:
    clean_up()
15
RoadieRich

あなたは今それを使うことを考えることができないとしても、あなたはそれを使うことがあるに違いない。想像力に溢れるサンプルです。

elseの場合:

a = [1,2,3]
try:
    something = a[2]
except:
    print "out of bounds"
else:
    print something

elseがなければ:

try:
    something = a[2]
except:
    print "out of bounds"

if "something" in locals():
    print something

エラーが発生しない場合は、ここで変数somethingを定義します。これをtryブロックの外で削除することはできますが、変数が定義されている場合は厄介な検出が必要になります。

10
Unknown

From エラーと例外#例外の処理 - docs.python.org

try ... exceptステートメントには、オプションのelse句があります。これは、存在する場合は、句を除くすべての句の後に続ける必要があります。 try句が例外を発生させない場合に実行されなければならないコードに役立ちます。例えば:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Else節の使用は、try節に追加されたコードを追加するよりも優れています。これは、try ... exceptステートメントによって保護されているコードによって引き起こされなかった例外を誤って捕捉するのを防ぐためです。

8
fedorqui

PEP 380try-elseのいい例があります。基本的には、アルゴリズムのさまざまな部分でさまざまな例外処理を行うことになります。

それはこのようなものです:

try:
    do_init_stuff()
except:
    handle_init_suff_execption()
else:
    try:
        do_middle_stuff()
    except:
        handle_middle_stuff_exception()

これにより、例外が発生した場所により近い例外処理コードを書くことができます。

6
itsadok

Pythonリファレンス を見ると、例外がない場合はelsetryの後に実行されるようです。オプションのelse節は、制御がtry節の末尾から離れたときに実行されます。 2 else節の例外は、上記のexcept節では処理されません。

python に飛び込むと、tryブロックで正しく理解できればモジュールをインポートしようとしますが、失敗すると例外が発生してデフォルトにバインドされますしかしそれがうまくいくとき、あなたはelseブロックに入り、必要なものをバインドするという選択肢があります(例と説明についてはリンクを見てください)。

catchブロックで作業を行おうとした場合、別の例外がスローされる可能性があります - elseブロックが便利なところだと思います。

5
stefanB

それでおしまい。 try-except節の 'else'ブロックは、試行した操作が成功したときに(そしてそのときだけ)実行されるコードに存在します。それは使用することができ、それは悪用することができます。

try:
    fp= open("configuration_file", "rb")
except EnvironmentError:
    confdata= '' # it's ok if the file can't be opened
else:
    confdata= fp.read()
    fp.close()

# your code continues here
# working with (possibly empty) confdata

個人的には、私はそれが好きで、適切なときにそれを使います。文を意味的にグループ化します。

3
tzot

ほとんどの答えは、try節の中にelse節の中にその資料を入れることができない理由に集中しているようです。 try文のquestion else節... に何が良いのかというと、else節のコードがなぜの後に行なえないのかを具体的に尋ねています。 try自体はブロックされていて、その質問はこの質問に重複していますが、ここではその質問に対する明確な回答は見ていません。私は感じます https://stackoverflow.com/a/3996378/1503120 この質問に非常によく答えます。私はまた、 https://stackoverflow.com/a/22579805/1503120 でさまざまな句のさまざまな意味を説明しようとしました。

3
jamadagni

おそらく用途は次のようになります。

#debug = []

def debuglog(text, obj=None):
    " Simple little logger. "
    try:
        debug   # does global exist?
    except NameError:
        pass    # if not, don't even bother displaying
    except:
        print('Unknown cause. Debug debuglog().')
    else:
        # debug does exist.
        # Now test if you want to log this debug message
        # from caller "obj"
        try:
            if obj in debug:
                print(text)     # stdout
        except TypeError:
            print('The global "debug" flag should be an iterable.')
        except:
            print('Unknown cause. Debug debuglog().')

def myfunc():
    debuglog('Made it to myfunc()', myfunc)

debug = [myfunc,]
myfunc()

多分これはあなたにも使用法を導くでしょう。

2
DevPlayer

データベースクエリを実行し、それらのクエリの結果を同じ種類/種類の別のデータベースに記録している状況では、try: ... else:構文が便利です。キューに送信されたデータベースクエリをすべて扱うワーカースレッドがたくさんあるとしましょう。

#in a long running loop
try:
    query = queue.get()
    conn = connect_to_db(<main db>)
    curs = conn.cursor()
    try:
        curs.execute("<some query on user input that may fail even if sanitized">)
    except DBError:
        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of failed query")
        logcurs.close()
        logconn.close()
    else:

        #we can't put this in main try block because an error connecting
        #to the logging DB would be indistinguishable from an error in 
        #the mainquery 

        #We can't put this after the whole try: except: finally: block
        #because then we don't know if the query was successful or not

        logconn = connect_to_db(<logging db>)
        logcurs = logconn.cursor()
        logcurs.execute("<update in DB log with record of successful query")
        logcurs.close()
        logconn.close()
        #do something in response to successful query
except DBError:
    #This DBError is because of a problem with the logging database, but 
    #we can't let that crash the whole thread over what might be a
    #temporary network glitch
finally:
    curs.close()
    conn.close()
    #other cleanup if necessary like telling the queue the task is finished

もちろん、スローされる可能性のある例外を区別できれば、これを使用する必要はありませんが、成功したコードに反応するコードが成功したピースと同じ例外をスローする可能性があり、 2番目に起こり得る例外を去るか、または成功したらすぐに戻る(これは私の場合はスレッドを殺すだろう)、そしてこれは役に立ちます。

1
sirlark

私はelseが間違っている可能性のある設定ファイルを扱うのに便利だとわかりました:

try:
    value, unit = cfg['lock'].split()
except ValueError:
    msg = 'lock monitoring config must consist of two words separated by white space'
    self.log('warn', msg)
else:
     # get on with lock monitoring if config is ok

lock設定を読み取る例外はロックモニタリングを無効にし、ValueErrorsは有用な警告メッセージをログに記録します。

1
Nick

私が考えることができる使用シナリオの1つは予測不可能な例外です、あなたがもう一度試みるならば回避することができます。たとえば、tryブロック内の演算に乱数が含まれているとします。

while True:
    try:
        r = random.random()
        some_operation_that_fails_for_specific_r(r)
    except Exception:
        continue
    else:
        break

ただし、例外が予測できる場合は、例外よりも事前に検証を常に選択する必要があります。しかし、すべてを予測できるわけではないので、このコードパターンにはその場所があります。

1
NeoWang

これが私がこのパターンを使うのを好むもう一つの場所です:

 while data in items:
     try
        data = json.loads(data)
     except ValueError as e:
        log error
     else:
        # work on the `data`
1
grdvnl

elseブロックは、すべてのexceptブロックで発生する機能を補完するために存在することがよくあります。

try:
    test_consistency(valuable_data)
except Except1:
    inconsistency_type = 1
except Except2:
    inconsistency_type = 2
except:
    # Something else is wrong
    raise
else:
    inconsistency_type = 0

"""
Process each individual inconsistency down here instead of
inside the except blocks. Use 0 to mean no inconsistency.
"""

この場合、inconsistency_typeがexcept以外の各ブロックに設定されているので、elseのエラーがない場合に動作が補完されます。

もちろん、私はこれをいつかあなた自身のコードで現れるかもしれないパターンとして説明しています。この特定のケースでは、とにかくtryブロックの前にinconsistency_typeを0に設定するだけです。

1
Wesley

プログラミングロジックが辞書に与えられたキーを持つエントリがあるかどうかに依存しているとしましょう。 if... else...構文を使ってdict.get(key)の結果をテストすることができます。

try:
    val = dic[key]
except KeyError:
    do_some_stuff()
else:
    do_some_stuff_with_val(val)
1
Gene