クラスで__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:」からエラーが返されることを本当に期待しています。
イテレータの定義 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().
反復による__getitem__
のサポートは、PEP234が反復性を主要な概念として導入したときにスムーズな移行を可能にする「レガシー機能」と見なすことができます。これは、__iter__
のないクラスにのみ適用され、その__getitem__
は整数0、1、&cを受け入れ、インデックスが高くなりすぎると(ある場合)、通常は「シーケンス」クラスがコード化されてIndexError
を発生させます。 __iter__
が現れる前(この方法でも新しいクラスのコーディングを妨げるものは何もありません)。
個人的に、私は新しいコードではこれに依存しませんが、非推奨ではなく、なくなることもないので(Python 3でもうまく機能します)、これはスタイルと好みの問題です) (「明示的は暗黙的より優れている」ので、__getitem__
が暗黙的にそれをサポートすることに依存するのではなく、明示的に反復可能性をサポートしたい-しかし、大きなものではない)。
__getitem__
はイテレータプロトコルよりも古く、過去に反復可能にするonlyの方法でした。そのため、繰り返しの方法として引き続きサポートされています。基本的に、反復のプロトコルは次のとおりです。
__iter__
方法。存在する場合は、新しい反復プロトコルを使用します。
それ以外の場合は、__getitem__
は、IndexErrorが発生するまで、整数値を大きくしていきます。
(2)これはこれを行う唯一の方法でしたが、反復のみをサポートするのに必要以上のものを想定するという欠点がありました。イテレーションをサポートするには、ランダムアクセスをサポートする必要がありました。ランダムアクセスは、ファイルやネットワークストリームなど、前に進むのは簡単ですが、後へ進むにはすべてを保存する必要があるため、はるかに高価でした。 __iter__
はランダムアクセスなしの反復を許可しましたが、ランダムアクセスは通常とにかく反復を許可するため、後方互換性を壊すことは悪いため、__getitem__
は引き続きサポートされます。
__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ループで繰り返し処理する対象です。
これは歴史的な理由からです。 Python 2.2より前のバージョンでは、__ getitem__はforループで反復できるクラスを作成する唯一の方法でした。2.2では__iter__プロトコルが追加されましたが、下位互換性を維持するために__getitem__は引き続きforループで機能します。
_cb[0]
_はcb.__getitem__(0)
と同じだからです。これについては pythonドキュメント を参照してください。