Pythonのイテレータが例外を発生させるのはなぜですか?


48

Javaの反復子の構文は次のとおりです(C#の構文に似ています)。

Iterator it = sequence.iterator();

while (it.hasNext()) {
    System.out.println(it.next());
}

理にかなっています。Pythonの同等の構文は次のとおりです。

it = iter(sequence)
while True:
    try:
        value = it.next() 
    except StopIteration:
        break
    print(value)

例外は、例外的な状況でのみ使用されることになっていると思いました。

Pythonが例外を使用して反復を停止するのはなぜですか?


回答:


50

aのtry-exceptブロックを明示的に記述することなく、その式を記述する非常にPython的な方法がありますStopIteration

# some_iterable is some collection that can be iterated over
# e.g., a list, sequence, dict, set, itertools.combination(...)

for value in some_iterable:
    print(value)

導入された理由とイテレータの背後にあるロジックの詳細を知りたい場合は、関連するPEP 234 255を参照してくださいStopIteration

pythonの一般的な原則は、何かをする1つの方法(参考文献を参照import this)、そしてできればpythonicメソッドが満たす、美しく、明示的で、読みやすく、単純な方法を持つことです。PythonはイテレータにhasNextメンバー関数を与えないため、同等のコードのみが必要です。イテレータを直接ループすることを人々に好む(そして、それを読んで例外をキャッチするために何か他のことをする必要がある場合)。

StopIterationイテレータの最後でこの例外を自動的にキャッチすることは理にかなっておりEOFError、ファイルの終わりを超えて読み取る場合に発生する例外に類似しています。


6
「Pythonの」方法は、「iter(sequence):の値の場合」というよりも、「シーケンスの値の場合:」のように思えます。投稿を更新しますか?
ヤムマルコビッチ

15
@ヤム:同意します。既存のシーケンスを取得して、forループを適用するためだけにイテレーターに変換するのは、Pythonではありません。シーケンスは既に反復可能であるため、a listからa への変換listiteratorは無意味です。私はどのようにすべきと同じ方法で、イテレータ、をループあなたべき任意の反復可能なオーバーループ(説明に、NullUserExceptionの開始点に従うことを最初の行を保ちlistsetstrtupledictfilegenerator、など)。it = itertools.combinations("ABCDE", 2)意味のあるイテレーターのより良い例を得るためのようなことをしたかもしれません。
ジンボブ博士11年

1
it = iter(sequence)必要ありません。
-Caridorc

2
@Caridorc-あなたがコメントを読んだ場合、あなたはあなたのポイントが扱われたと思います。それは必要ではなく、質問の出発点(彼らが明示的に尋ねていた場所iterators)に従うために行われたのでiter、明示的にiterator(try type([])list)vs type(iter([]))listiterator))を生成する必要があります。
ジンボブ博士15年

//、@ drjimbob、この質問に対する2番目のコメントで優れた点を挙げます。私はイテラブルの高度な機能に少し慣れていないので、コメントを読んでいなければそれを理解できませんでした。質問の最初の主要部分である「Pythonの方法」にどのように変更できるかという点を見ることができれば、貧しい独学の魂の多くに利益をもたらすと思います。
ネイサンバサネーゼ

28

pythonが例外を使用して反復を停止する理由は、PEP 234に記載されています。

反復の終了を通知する例外がそれほど高価ではないかどうかが疑問視されています。StopIteration例外のいくつかの代替案が提案されています:終了を通知する特別な値End、反復子が終了したかどうかをテストする関数end()、IndexError例外を再利用することです。

  • 特別な値には、シーケンスにその特別な値が含まれる場合、そのシーケンスのループが警告なしに途中で終了するという問題があります。nullで終わるC文字列の経験がこれが引き起こす問題を教えていない場合、特別なEnd値が組み込みであると仮定して、Pythonイントロスペクションツールがすべての組み込み名のリストを反復処理する問題を想像してください名前で!

  • end()関数を呼び出すには、反復ごとに2回の呼び出しが必要です。2回の呼び出しは、1回の呼び出しと例外のテストよりもはるかに高価です。特に、タイムクリティカルなforループは、例外を非常に安価にテストできます。

  • IndexErrorを再利用すると、真のエラーになる可能性があるため、混乱を引き起こす可能性があります。

注:シーケンスをループする慣用的なPythonの方法は次のとおりです。

for value in sequence:
    print (value)

20

それは哲学の違いです。Pythonicの設計哲学はEAFPです:

許可よりも許しを求める方が簡単です。この一般的なPythonコーディングスタイルは、有効なキーまたは属性が存在することを前提とし、仮定が偽であると判明した場合に例外をキャッチします。このクリーンで高速なスタイルは、多数のステートメントtryexceptステートメントの存在によって特徴付けられます。この手法は、Cなどの他の多くの言語に共通のLBYLスタイルとは対照的です...


7

Java実装にhasNext()メソッドがあるため、を実行する前に空のイテレータを確認できますnext()。あなたが呼び出しを行うとnext()左の要素を持たないJavaのイテレータに、NoSuchElementExceptionスローされます

Pythonのtry..exceptと同様に、Javaでtry..catchを効果的に実行できます。はい、前の回答によると、哲学はPythonの世界では非常に重要です。

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