next()
メソッドをチェックできますが、それで十分ですか?イデオマティックな方法はありますか?
Python 2.6以降では、このような動作チェックの設計されたイディオムは、標準ライブラリのcollections
モジュールにある抽象基本クラスを使用した「メンバーシップチェック」です。
_>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
_
確かに、この種のチェックは、新しい抽象基本クラスの主要な設計上の理由です(2番目に重要なのは、場合によっては「ミックスイン機能」を提供することです。そのため、これらは単なるインターフェイスではなくABCですが、そうではありません。 t _collections.Iterable
_に適用され、isinstance
またはissubclass
でそのようなチェックを許可するために厳密に存在します。 ABCを使用すると、実際には継承しないクラスをサブクラスとして「登録」できるため、そのようなクラスをそのようなチェックのABCの「サブクラス」にすることができます。また、特別なメソッド(この場合は___iter__
_)に必要なすべてのチェックを内部で実行できるため、実行する必要はありません。
Pythonの古いリリースで立ち往生している場合は、「許可よりも許しを求める方がよい」:
_def isiterable(x):
try: iter(x)
except TypeError: return False
else: return True
_
しかし、それは新しいアプローチほど速くて簡潔ではありません。
この特殊なケースでは、特殊なケースの文字列(反復可能ですが、ほとんどのアプリケーションコンテキストはとにかく「スカラー」として扱いたい)が必要になることがよくあります。反復可能性をチェックするために使用しているアプローチが何であれ、そのような特別なケーシングが必要な場合は、isinstance(x, basestring)
のチェックを追加するだけです。例:
_def reallyiterable(x):
return not isinstance(x, basestring) and isinstance(x, collections.Iterable)
_
編集:コメントで指摘されているように、質問は、オブジェクトが反復可能であるかどうかではなく、反復可能であるかどうかに焦点を当てています***(すべての反復子は反復可能です) 、ただしその逆ではありません-すべてのイテレータがイテレータであるとは限りません)。 isinstance(x, collections.Iterator)
は、その状態を具体的にチェックするための完全に類似した方法です。
オブジェクトがイテレータプロトコルを実装している場合、そのオブジェクトは反復可能です。__iter__()
メソッドの存在を次の方法で確認できます。
hasattr(object,'__iter__')
in Python 2.xこのアプローチでは、strオブジェクトや、unicode、xrange、bufferなどの他の組み込みシーケンスタイプが欠落しています。Python 3で機能します。
別の方法は、iterメソッドでテストすることです:
try:
iter(object)
except TypeError:
#not iterable
イテレータになるには、オブジェクトは次の3つのテストに合格する必要があります。
obj
には___iter__
_メソッドがありますobj
にはnext
メソッド(または___next__
_ in Python 3)obj.__iter__()
はobj
を返しますしたがって、独自のテストは次のようになります。
_def is_iterator(obj):
if (
hasattr(obj, '__iter__') and
hasattr(obj, 'next') and # or __next__ in Python 3
callable(obj.__iter__) and
obj.__iter__() is obj
):
return True
else:
return False
_
pythonソースコードドキュメントコメントからの回答:
{pythonインストールパス} /Versions/3.5/lib/python3.5/types.py
# Iterators in Python aren't a matter of type but of protocol. A large
# and changing number of builtin types implement *some* flavor of
# iterator. Don't check the type! Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.
他の回答が示唆しているよりも良い方法があります。
Pythonには、Iterable
とIterator
の2種類があります。オブジェクトはIterable
を提供できる場合はIterator
です。オブジェクトでiter()
を使用するとそうなります。 next()
を使用してその要素を順番に参照できる場合、オブジェクトはIterator
です。たとえば、map()
はIterator
を返し、list
はIterable
です。
ここに 詳細 があります。
以下のコードは、これらのタイプをチェックする方法を示しています。
from collections.abc import Iterable, Iterator
r = [1, 2, 3]
e = map(lambda x:x, r)
print(isinstance(r, Iterator)) # False, because can't apply next
print(isinstance(e, Iterator)) # True
print(isinstance(r, Iterable)) # True, because can apply iter()
print(isinstance(e, Iterable)) # True, note iter() returns self
この例は、本Effective Pythonからのものであり、この post に示されています。
Iterableはイテレータを生成します。イテレータもイテレータですが、イテレータとして生成されます。
>>> list_iter = iter([]) >>> iter(list_iter) is list_iter True
質問はイテレータではなくイテレータに関するものであり、イテレータの使用を検討しているため、これを行う最も簡単でPythonの方法
iterable = [1,2]
iterator = iter(iterable)
def isIterator(obj):
try:
next(obj, None)
return True
except TypeError:
return False
>>> isIterator(iterable)
False
>>> isIterator(iterator)
True
はい。 next()をチェックするだけで十分です