73

クラスで __getitem__ を定義すると反復可能になるのはなぜですか?

たとえば、私が書いた場合:

class b:
  def __getitem__(self, k):
    return k

cb = b()

for k in cb:
  print k

出力が得られます:

0
1
2
3
4
5
6
7
8
...

「for k in cb:」からエラーが返されることを期待しています。

4

6 に答える 6

73

反復のサポートは__getitem__、PEP234 が主要な概念として反復可能性を導入したときに、よりスムーズな移行を可能にする「レガシー機能」と見なすことができます。これは、整数 0、1、&c__iter__を受け入れないクラスにのみ適用され、インデックスが高くなりすぎると発生します (発生した場合)。通常、以前にコーディングされた「シーケンス」クラスが表示されます (ただし、この方法で新しいクラスをコーディングすることを妨げるものは何もありません)。__getitem__IndexError__iter__

個人的には、新しいコードではこれに依存したくありませんが、廃止されたり、なくなったりするわけではありません (Python 3 でも問題なく動作します)。反復可能性を暗黙的にサポートすることに頼るのではなく、反復可能性を明示的にサポートしたい__getitem__のですが、大したことではありません)。

于 2009-05-29T15:37:35.130 に答える
54

イテレータを定義するPEP234を見ると、次のように書かれています。

1. An object can be iterated over with "for" if it implements
   __iter__() or __getitem__().

2. An object can function as an iterator if it implements next().
于 2009-05-29T15:29:22.177 に答える
39

__getitem__反復子プロトコルよりも前から存在し、過去には反復可能にする唯一の方法でした。そのため、繰り返しの方法として引き続きサポートされています。基本的に、反復のプロトコルは次のとおりです。

  1. メソッドを確認し__iter__ます。存在する場合は、新しい反復プロトコルを使用します。

  2. __getitem__それ以外の場合は、 IndexError が発生するまで、連続して大きな整数値で呼び出してみてください。

(2) はこれを行う唯一の方法でしたが、反復をサポートするために必要以上のことを想定しているという欠点がありました。反復をサポートするには、ランダム アクセスをサポートする必要がありました。ランダム アクセスをサポートする必要がありました。これは、ファイルやネットワーク ストリームなど、前に進むのは簡単でしたが、後ろに進むにはすべてを保存する必要があるため、はるかに高価でした。 __iter__ランダムアクセスなしで反復を許可しましたが、ランダムアクセスは通常、とにかく反復を許可し、下位互換性を壊すと悪いため、__getitem__引き続きサポートされます。

于 2009-05-29T15:38:10.153 に答える
8

__getitem__反復を含む特別な動作をオブジェクトに追加 するなどの特別なメソッド。

http://docs.python.org/reference/datamodel.html#object. ゲットアイテム

「 for ループは、シーケンスの終わりを適切に検出できるように、不正なインデックスに対して IndexError が発生することを期待しています。」

シーケンスの終わりを知らせるために IndexError を発生させます。

あなたのコードは基本的に次のものと同等です:

i = 0
while True:
    try:
        yield object[i]
        i += 1
    except IndexError:
        break

object は for ループで繰り返し処理するものです。

于 2009-05-29T15:28:06.157 に答える
5

これは歴史的な理由によるものです。Python 2.2 より前は、__getitem__ が for ループで反復できるクラスを作成する唯一の方法でした。2.2 では __iter__ プロトコルが追加されましたが、下位互換性を維持するために __getitem__ は for ループで引き続き機能します。

于 2009-05-29T15:38:23.337 に答える
2

cb[0]と同じだからですcb.__getitem__(0)これについては、 Python のドキュメントを参照してください。

于 2009-05-29T15:26:14.180 に答える