web-dev-qa-db-ja.com

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

クラスで__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:」からエラーが返されることを本当に期待しています。

57
grieve

イテレータの定義 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().
46
Edward Dale

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

個人的に、私は新しいコードではこれに依存しませんが、非推奨ではなく、なくなることもないので(Python 3でもうまく機能します)、これはスタイルと好みの問題です) (「明示的は暗黙的より優れている」ので、__getitem__が暗黙的にそれをサポートすることに依存するのではなく、明示的に反復可能性をサポートしたい-しかし、大きなものではない)。

60
Alex Martelli

__getitem__はイテレータプロトコルよりも古く、過去に反復可能にするonlyの方法でした。そのため、繰り返しの方法として引き続きサポートされています。基本的に、反復のプロトコルは次のとおりです。

  1. __iter__ 方法。存在する場合は、新しい反復プロトコルを使用します。

  2. それ以外の場合は、__getitem__は、IndexErrorが発生するまで、整数値を大きくしていきます。

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

25
Brian

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

http://docs.python.org/reference/datamodel.html#object。getitem

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

IndexErrorを発生させて、シーケンスの終わりを通知します。

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

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

Whereオブジェクトは、forループで繰り返し処理する対象です。

6
FogleBird

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

5
Ants Aasma

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

2
Jorenko