最初に明確にしたいのは、「イテレータ」とは何なのかということではありません。
これは、「反復可能」という用語がPythonの doc で定義されている方法です。
反復可能
一度に1つのメンバーを返すことができるオブジェクト。反復可能オブジェクトの例には、すべてのシーケンス型(リスト、str、タプルなど)と一部の非-dictのようなシーケンスタイプ、ファイルオブジェクト、__ iter __()または__getitem __()メソッドで定義したクラスのオブジェクト。
イテラブルは、forループや、シーケンスが必要な他の多くの場所(Zip()、map()など)で使用できます。反復可能なオブジェクトが引数として組み込み関数iter()に渡されると、オブジェクトの反復子が返されます。この反復子は、値のセットを1回パスするのに適しています。イテラブルを使用する場合、通常はiter()を呼び出したり、イテレータオブジェクトを自分で処理したりする必要はありません。 forステートメントはそれを自動的に行い、ループの期間中イテレータを保持する一時的な名前のない変数を作成します。
イテレータ、シーケンス、ジェネレータもご覧ください。
他の人が示唆したように のように、isinstance(e, collections.Iterable)
を使用することは、オブジェクトが反復可能かどうかを確認する最もPython的な方法です。
そこでPython 3.4.3:
from collections.abc import Iterable
class MyTrain:
def __getitem__(self, index):
if index > 3:
raise IndexError("that's enough!")
return index
for name in MyTrain():
print(name) # 0, 1, 2, 3
print(isinstance(MyTrain(), Iterable)) # False
結果はかなり奇妙です:MyTrain
は__getitem__
メソッドを定義していますが、一度に1つの数値を返すことができることは言うまでもなく、反復可能なオブジェクトとは見なされません。
次に、__getitem__
を削除し、__iter__
メソッドを追加しました。
from collections.abc import Iterable
class MyTrain:
def __iter__(self):
print("__iter__ called")
pass
print(isinstance(MyTrain(), Iterable)) # True
for name in MyTrain():
print(name) # TypeError: iter() returned non-iterator of type 'NoneType'
反復中に何も生成できないにもかかわらず、「真の」反復可能オブジェクトと見なされます。
それで私は何かを誤解しましたか、それともドキュメントが間違っていますか?
ここでの混乱のポイントは、__getitem__
doesを実装してもオブジェクトを反復できることですが、それは定義されているインターフェースの一部ではありません Iterable
。
抽象基本クラス は、仮想サブクラス化の形式を許可します。指定されたメソッドを実装するクラス(Iterable
の場合、__iter__
のみ)はisinstance
とissubclass
をABCのサブクラスにする明示的に継承しない場合でも。ただし、メソッドの実装実際に機能するかどうかは確認されませんが、提供されているかどうかは確認されません。
詳細については、ABCを導入した PEP-3119 を参照してください。
isinstance(e, collections.Iterable)
の使用は、オブジェクトが反復可能かどうかを確認する最もPython的な方法です
同意しません;私は duck-typing とだけを使用してオブジェクトを反復処理します。オブジェクトが反復可能でない場合、TypeError
が発生します。これは、反復不可能な入力を処理する場合は関数でキャッチでき、そうでない場合は呼び出し元までパーコレートすることができます。これにより、オブジェクトが反復を実装することを決定した方法が完全に回避され、最適なタイミングでそれが実行されるかどうかがわかります。
もう少し追加すると、あなたが引用したドキュメントはわずかに誤解を招くと思います。 iter
docs を引用すると、おそらくこれが明確になります。
objectは、反復プロトコル(
__iter__()
メソッド)をサポートするコレクションオブジェクトであるか、シーケンスプロトコル(__getitem__()
メソッドで始まり、0
)。
これにより、どちらのプロトコルでもオブジェクトを反復可能にしても、実際の"iteration protocol"は1つだけであり、isinstance(thing, Iterable)
がテストするのはこのことです。したがって、最も一般的なケースで"反復できるもの"を確認する1つの方法は次のようになると結論付けることができます。
isinstance(thing, (Iterable, Sequence))
ただし、これには__len__
を__getitem__
とともに"virtually sub-class"Sequence
に実装する必要もあります。
それis反復可能です。ただし、abc.Iterable
から継承していないため、当然Pythonは、そのクラスの子孫であるとは報告しません。反復可能であること、およびそのベースからの子孫の2つクラス-まったく別です。