イテレータ、反復可能、反復とは正確には何ですか?


442

Pythonの「反復可能」、「反復子」、「反復」の最も基本的な定義は何ですか?

複数の定義を読みましたが、まだ理解できないため、正確な意味を特定できません。

誰かが簡単な言葉で3つの定義を手伝ってくれませんか?

回答:


530

イテレーションは、何かの各アイテムを次々と取得するための一般的な用語です。明示的または暗黙的なループを使用して、アイテムのグループ、つまり反復を処理するとき。

Pythonでは、反復可能オブジェクト反復子には特定の意味があります。

反復可能であるオブジェクトで__iter__返すメソッド反復子を、または定義する__getitem__ゼロから始まるシーケンシャルインデックスを取る(および提起することができない方法IndexErrorインデックスがもはや有効である場合に)。つまり、イテラブルは、イテレーターを取得できるオブジェクトです。

反復子が持つオブジェクトであるnext(パイソン2)または__next__(Pythonの3)の方法。

Pythonでforループ、or map、リスト内包などを使用すると、nextメソッドが自動的に呼び出され、イテレータから各項目が取得されるため、反復プロセスが実行されます

学習を始めるのに適した場所は、チュートリアルイテレータセクションと標準タイプのページのイテレータタイプセクションです。基本を理解したら、関数型プログラミングHOWTOのイテレータセクションを試してください。


1
とメソッドのcollections.abc.AsyncIteratorテストに注意してください。これは3.6の新しい追加です。__aiter____anext__
Janus Troelsen、2018

1
@jlhなぜ__len__必ず反復に関連付けられるのですか?何かの長さを知ることは、それを反復するのにどのように役立ちますか?
シャドウトーカー2018

2
@shadowtalkerはどのインデックスが有効であるかを知るのに役立つので、どのインデックスをで使用できるかがわかります__getitem__
jlh

4
@jlh非常に独断的なふるまい行動を提案しているようです。それは考える{'a': 'hi', 'b': 'bye'}2の長さを有するが、0、1、または2によってインデックス付けすることができない
shadowtalker

2
@shadowtalker。しかし、辞書には__iter__方法があります。jlhは、特に「__getitem__0から始まる順次インデックスを取得できるメソッド」を定義しているため、反復可能なオブジェクトを参照していると思います。
リッチ

337

Pythonクラスを教える際に使用する説明は次のとおりです。

ITERABLEは次のとおりです。

  • ループできるもの(つまり、文字列またはファイルをループできる)または
  • forループの右側に表示できるもの: for x in iterable: ...または
  • あなたが呼び出すことができるものはすべてiter()ITERATORを返します: iter(obj)または
  • __iter__新しいITERATORを返すことを定義するオブジェクト、または__getitem__インデックス付きルックアップに適したメソッドがある場合があります。

ITERATORはオブジェクトです。

  • イテレーション中の場所を記憶する状態で、
  • 次の__next__方法で:
    • 反復の次の値を返します
    • 次の値を指すように状態を更新します
    • レイズによって行われたときに信号を送る StopIteration
  • これは自己反復可能です(つまり、__iter__を返すメソッドがあることを意味しますself)。

ノート:

  • __next__Python 3 のメソッドはPython 2で記述さnextれており、
  • 組み込み関数next()は、渡されたオブジェクトでそのメソッドを呼び出します。

例えば:

>>> s = 'cat'      # s is an ITERABLE
                   # s is a str object that is immutable
                   # s has no state
                   # s has a __getitem__() method 

>>> t = iter(s)    # t is an ITERATOR
                   # t has state (it starts by pointing at the "c"
                   # t has a next() method and an __iter__() method

>>> next(t)        # the next() function returns the next value and advances the state
'c'
>>> next(t)        # the next() function returns the next value and advances
'a'
>>> next(t)        # the next() function returns the next value and advances
't'
>>> next(t)        # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration

>>> iter(t) is t   # the iterator is self-iterable

フレッシュイテレータとはどういう意味ですか?
lmiguelvargasf 2017

13
@lmiguelvargasf「使い果たされた、または部分的に消費された」ではなく、「新しくて消費されなかった」のような「新鮮」。新しいイテレータは最初から始まり、部分的に使用されたイテレータは中断したところから処理を開始するという考え方です。
レイモンドヘッティンガー2017

2番目、3番目、4番目の箇条書きは、特定のpython構成体、組み込み、またはメソッド呼び出しに関して、あなたの意味を明確に示しています。しかし、最初の箇条書き(「ループすることができるもの」)には、その明確さがありません。また、2番目の弾丸はforループに関するものであり、1番目の弾丸は「ループオーバー」に関するものであるため、1 番目の弾丸は2番目の弾丸と重複しているように見えます。これらに対処できますか?
噴水

2
PLSの再フレージング「何であなたの缶コール考えるiter()」「あなたに渡すことができるものとしてiter()、」
源泉

98

上記の答えは素晴らしいですが、私が見たことのほとんどとして、私のような人々のために区別を十分に強調しないでください。

また、人々は__foo__()以前に「Xはメソッドを持つオブジェクト」のような定義を置くことによって「あまりにもPythonic」になる傾向があります。そのような定義は正しいです。それらはダックタイピングの哲学に基づいていますが、メソッドに焦点を当てるのは、その単純さで概念を理解しようとするときに中間になる傾向があります。

だから私は私のバージョンを追加します。


自然言語で

  • 反復は、要素の行で一度に1つの要素を取得するプロセスです。

Pythonでは、

  • iterableは、まあ、反復可能であるオブジェクトです。つまり、forループなどで繰り返し使用できることを意味します。どうやって?イテレータを使用する。以下に説明します。

  • ... イテレータは、実際に反復を行う方法を定義するオブジェクトです。具体的には、次の要素は何ですか。それがnext()メソッドを持たなければならない理由 です。

イテレータ自体も反復可能ですが、その項目が以前のの呼び出しによって消費されたかどうかに関係なく、__iter__()メソッドが同じオブジェクト(self)を返す点が異なりますnext()


では、Pythonインタープリターはfor x in obj:ステートメントを見て、どう思いますか?

見て、forループ。イテレータの仕事のように見えます...取得しましょう。...このobj男がいるので、彼に聞いてみましょう。

「さんobj、イテレータはありますか?」(...呼び出しiter(obj)、呼び出し obj.__iter__()、光沢のある新しいイテレータを楽しそうに渡し_iます)

OK、それは簡単でした...それでは反復を始めましょう。(x = _i.next()... x = _i.next()...)

Mr. objがこのテストに成功したので(特定のメソッドが有効なイテレータを返すことで)、形容詞で彼に報酬を与えますobj。これで、彼を「反復可能なMr. 」と呼ぶことができます。

ただし、単純なケースでは、通常、イテレータとイテラブルを個別に使用するメリットはありません。したがって、オブジェクトを1つだけ定義します。これは、独自のイテレータでもあります。(Pythonは、_i配布されたものobjがそれほど光沢があるわけではなく、objそれ自体が本当に気にしません。)

これが、私が見たほとんどの例(および私を何度も混乱させていたもの)で、次のことを確認できる理由です。

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

の代わりに

class Iterator(object):
    def next(self):
        pass

class Iterable(object):
    def __iter__(self):
        return Iterator()

ただし、イテレータをイテラブルから分離することでメリットが得られる場合もあります。たとえば、1行のアイテムで「カーソル」を増やしたい場合などです。たとえば、「現在の」要素と「今後の」要素を操作する場合は、両方に別々のイテレータを使用できます。または、巨大なリストからプルする複数のスレッド:各スレッドは、すべてのアイテムをトラバースする独自のイテレータを持つことができます。参照してください@レイモンドさん@ glglglの上記の答え。

あなたが何ができるか想像してみてください:

class SmartIterableExample(object):

    def create_iterator(self):
        # An amazingly powerful yet simple way to create arbitrary
        # iterator, utilizing object state (or not, if you are fan
        # of functional), magic and nuclear waste--no kittens hurt.
        pass    # don't forget to add the next() method

    def __iter__(self):
        return self.create_iterator()

ノート:

  • もう一度繰り返します。反復子は反復可能ではありません。イテレータをforループの「ソース」として使用することはできません。どのようなforループは、主に必要なのはある__iter__() (とリターンの何かということnext())。

  • もちろん、forこれが唯一の反復ループではないため、上記は他のいくつかの構成にも適用されます(while...)。

  • イテレータnext()はStopIterationをスローして反復を停止できます。ただし、必ずしも繰り返す必要はありません。

  • 上記の「思考プロセス」では、_i実際には存在しません。私はその名前を作りました。

  • Python 3.xに小さな変更があります。next()メソッド(組み込みではない)を呼び出さなければなりません__next__()。はい、それはずっとそうだったはずです。

  • 次のように考えることもできます:iterableにはデータがあり、イテレータは次のアイテムをプルします

免責事項:私はPythonインタープリターの開発者ではないので、インタープリターが何を「考える」のか本当にわかりません。上記の黙想は、Python初心者の他の説明、実験、および実際の経験からトピックをどのように理解するかを示すデモにすぎません。


1
これは素晴らしいですが、私はまだ少し混乱しています。あなたの黄色いボックスはforループにイテレーターが必要だと言っていると思いました(「見て、forループ。イテレーターの仕事のように見えます...始めましょう」)。しかし、最後のメモで「イテレータはforループ内のソースとして使用できない」と言っています...?
レースオタマジャクシ

なぜpassこれらのnext定義のコードだけを入れるのですか?次は何かを返さなければならないので、誰かが次のものを取得する方法を実装しなければならないことを単にあなたが意味すると仮定します。
nealmcb

@nealmcbはい、私はそれが過去を意味していたと思います。(結局のところ、それpassがの目的です。)
アロア・マダル

@AloisMahdalああ、私は前にその使用を見たことがありませんでした。を見るとpass、構文上の理由でそこにあると思います。私は非常に興味深い省略オブジェクトで答えに出くわしました...。「後で実行する」ブロックを示すために使用できます。NotImplementedもご利用いただけます。
nealmcb

イテレータとイテラブルの違いを強調しているのが好きですが、この答えは矛盾しています。最初に、「イテレータ自体も反復可能」(Pythonのドキュメントに記載されいるものと一致します)と記述します。しかし、その後、次のように記述します。 ' イテレータは反復可能ではありません。イテレータはforループの「ソース」として使用できません。私はあなたの答えの要点を理解し、そうでなければそれが好きですが、これを修正することには利益があると思います。
リッチ

22

反復可能オブジェクトは、__iter__()メソッドを持つオブジェクトです。list()sやtuple()s などのように、数回反復する可能性があります。

イテレータは、反復するオブジェクトです。__iter__()メソッドによって返され、独自の__iter__()メソッドを介して自身を返し、メソッドを持っていnext()ます(__next__()3.xの場合)。

反復は、このnext()応答を呼び出すプロセスです。__next__()それが上がるまでStopIteration

例:

>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1

それで、本当にそれは単にコンテナのオブジェクトを通過するオブジェクトなのでしょうか?これは役に立ちましたか?
thechrishaddad

多くの場合、常にではありません。ジェネレータ、ファイル、またはデータベースカーソルは1回だけ反復できるため、独自の反復子になります。
glglgl 2012年

私はb2がb1から独立している必要はないと思いますか?この特別なケースでは、それは独立していますIterable。確かに私はそれを独立させないで有効なものにすることもできます。
Bin

@Binはい。でIteratorあり、常にIterable、そしてそれ自体であるIteratorので、の2つの呼び出しは、iter()必ずしも2つの独立したを与えるわけではありませんIterator
glglgl 2016年

13

これが私のチートシートです:

 sequence
  +
  |
  v
   def __getitem__(self, index: int):
  +    ...
  |    raise IndexError
  |
  |
  |              def __iter__(self):
  |             +     ...
  |             |     return <iterator>
  |             |
  |             |
  +--> or <-----+        def __next__(self):
       +        |       +    ...
       |        |       |    raise StopIteration
       v        |       |
    iterable    |       |
           +    |       |
           |    |       v
           |    +----> and +-------> iterator
           |                               ^
           v                               |
   iter(<iterable>) +----------------------+
                                           |
   def generator():                        |
  +    yield 1                             |
  |                 generator_expression +-+
  |                                        |
  +-> generator() +-> generator_iterator +-+

クイズ:どうですか...

  1. すべてのイテレータはイテラブルですか?
  2. コンテナオブジェクトの__iter__()メソッドはジェネレータとして実装できますか?
  3. __next__メソッドを持つイテラブルは必ずしもイテレータではありませんか?

答え:

  1. すべてのイテレータには__iter__メソッドが必要です。持つ__iter__ことは反復可能であるのに十分です。したがって、すべての反復子は反復可能です。
  2. 場合は__iter__、それが(イテレータを返すべきであると呼ばれreturn <iterator>、上記の図に)。ジェネレータを呼び出すと、イテレータの一種であるジェネレータイテレータが返されます。

    class Iterable1:
        def __iter__(self):
            # a method (which is a function defined inside a class body)
            # calling iter() converts iterable (tuple) to iterator
            return iter((1,2,3))
    
    class Iterable2:
        def __iter__(self):
            # a generator
            for i in (1, 2, 3):
                yield i
    
    class Iterable3:
        def __iter__(self):
            # with PEP 380 syntax
            yield from (1, 2, 3)
    
    # passes
    assert list(Iterable1()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3]
    
  3. 次に例を示します。

    class MyIterable:
    
        def __init__(self):
            self.n = 0
    
        def __getitem__(self, index: int):
            return (1, 2, 3)[index]
    
        def __next__(self):
            n = self.n = self.n + 1
            if n > 3:
                raise StopIteration
            return n
    
    # if you can iter it without raising a TypeError, then it's an iterable.
    iter(MyIterable())
    
    # but obviously `MyIterable()` is not an iterator since it does not have
    # an `__iter__` method.
    from collections.abc import Iterator
    assert isinstance(MyIterable(), Iterator)  # AssertionError
    

1
クイズでは、最初の箇条書きしか分かりませんでした。つまり、イテレータは__iter__メソッドを持つため、イテラブルになります。この回答を編集して、2番目と3番目のポイントについて詳しく説明してください
AnV

@AnV:私が理解している限り:re 2 .: __iter__()イテレータを返します。ジェネレータはイテレータなので、この目的で使用できます。3再:私はここでしか推測することができますが、私はあればと思い__iter__()不足している、または戻りませんself反復子があるため、それは、イテレータではありません__iter__()返すことがありますself
glglgl

10

それが誰かに役立つかどうかはわかりませんが、頭の中の概念を視覚化して理解を深めたいと思っています。だから私は小さな息子がいるので、レンガと白い紙で反復可能/反復のコンセプトを視覚化します。

暗い部屋にいて、床には息子用のレンガがあるとします。異なるサイズ、色のレンガは今は問題ではありません。このようなレンガが5つあるとします。これらの5つのレンガはオブジェクトとして説明できます。たとえば、レンガキットとしましょう。このレンガキットを使用すると、多くのことができます。1つ取り、2つ目、3つ目を取り、レンガの場所を変更し、最初のレンガを2つ目のブロックの上に置くことができます。私たちはそれらでいろいろなことをすることができます。したがって、このレンガキットは、各レンガを通過して何かを行うことができるため、反復可能なオブジェクトまたはシーケンスです。私たちができるのは私の小さな息子のようにだけです。一度に1つのレンガ遊ぶことができます。だから私はこのレンガキットが自分自身であることを想像します反復可能

今、私たちは暗い部屋にいることを思い出してください。またはほとんど暗い。問題は、それらのレンガ、それらの色、形などがはっきりと見えないことです。したがって、それらを使って何かをしたい場合、つまり、それらを繰り返し処理する場合でも、何でどのようにしているかはわかりません。暗すぎます。

私たちにできることは、最初のレンガの近くに–レンガキットの要素として–最初のレンガ要素がどこにあるかを確認するために、白い蛍光紙を置くことができます。そして、キットからレンガを取り出すたびに、暗い部屋でそれを確認できるように、白い紙を次のレンガに交換します。この白い紙はイテレータにすぎません。それもオブジェクトです。しかし、イテラブルオブジェクトの要素を操作および操作できるオブジェクト、つまりレンガキットです。

ところで、IDLEで次のことを試してTypeErrorを受け取ったときの初期の間違いを説明します。

 >>> X = [1,2,3,4,5]
 >>> next(X)
 Traceback (most recent call last):
    File "<pyshell#19>", line 1, in <module>
      next(X)
 TypeError: 'list' object is not an iterator

リストXはレンガのキットでしたが、白い紙ではありませんでした。最初にイテレータを見つける必要がありました:

>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>

それが役立つかどうかはわかりませんが、私には役立ちました。誰かがコンセプトの視覚化を確認/修正できたら、ありがたいです。もっと学ぶのに役立ちます。


6

反復可能な: -反復可能である何かが反復可能です。リスト、文字列などのようなシーケンス。__getitem__メソッドまたはメソッドのいずれかを持っています__iter__iter()そのオブジェクトで関数を使用すると、イテレータが取得されます。

Iterator:- iter()関数からiteratorオブジェクトを取得したとき。__next__()メソッド(python3の場合)または単にnext()(python2の場合)を呼び出して、要素を1つずつ取得します。このクラスまたはこのクラスのインスタンスは、イテレーターと呼ばれます。

ドキュメントから:-

イテレータの使用はPythonに浸透し、統一します。背後で、forステートメントがiter() コンテナオブジェクトを呼び出し  ます。この関数は__next__() 、コンテナ内の要素に1つずつアクセスするメソッドを定義する反復子オブジェクトを返します  。要素がなくなると  __next__() 、StopIteration例外が発生し、forループに終了を通知します。 組み込み関数__next__() を使用してメソッドを  呼び出すことができます  next()。この例は、すべてがどのように機能するかを示しています。

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

クラスの例:-

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

4

私はあなたがドキュメントよりもはるかに簡単にそれを得ることができるとは思いませんが、私は試してみます:

  • 反復可能なをすることができるものです繰り返しオーバー。実際には、通常シーケンスを意味します。たとえば、始まりと終わりがあり、その中のすべての項目を通過する方法があります。
  • Iteratorは、iterableの次の(または最初の)アイテムを提供(または保持)するヘルパー疑似メソッド(または疑似属性)と考えることができます。(実際には、メソッドを定義するのは単なるオブジェクトですnext()

  • 反復は、Merriam-Webster の単語の定義によっておそらく最もよく説明されます

b:一連のコンピューター命令を指定された回数または条件が満たされるまで繰り返す—再帰を比較する


3
iterable = [1, 2] 

iterator = iter(iterable)

print(iterator.__next__())   

print(iterator.__next__())   

そう、

  1. iterableあるオブジェクトことができ超えるループが。たとえば、リスト、文字列、タプルなど。

  2. オブジェクトでiter関数を使用するiterableと、イテレータオブジェクトが返されます。

  3. このイテレータオブジェクトに__next__、(Python 3またはnextPython 2 のみで)という名前のメソッドがあり、これを使用して反復可能オブジェクトの各要素にアクセスできます。

したがって、上記のコードの出力は次のようになります。

1

2


3

イテラブルには、__iter__毎回新しいイテレータをインスタンス化するメソッドがあります。

イテレータは、__next__個々のアイテムを返すメソッドとを返すメソッドを実装__iter__しますself

したがって、反復子も反復可能ですが、反復可能ではありません。

Luciano Ramalho、Fluent Python。


2

イテラブルとイテレータを扱う前に、イテラブルとイテレータを決定する主な要素はシーケンスです

シーケンス:シーケンスはデータのコレクションです

Iterable:Iterableは、__iter__メソッドをサポートするシーケンス型オブジェクトです。

Iterメソッド:Iterメソッドはシーケンスを入力として取り、イテレーターとして知られるオブジェクトを作成します

イテレーター:イテレーターは、次のメソッドを呼び出し、シーケンスを横切るオブジェクトです。次のメソッドを呼び出すと、現在横断しているオブジェクトが返されます。

例:

x=[1,2,3,4]

xは、データのコレクションで構成されるシーケンスです

y=iter(x)

呼び出すiter(x)と、xオブジェクトにiterメソッドがある場合にのみイテレータが返されます。それ以外の場合は例外が発生します。イテレータを返す場合、yは次のように割り当てられます。

y=[1,2,3,4]

yはイテレータなので、next()メソッドをサポートします

nextメソッドを呼び出すと、リストの個々の要素が1つずつ返されます。

シーケンスの最後の要素を返した後、次のメソッドを再度呼び出すと、StopIterationエラーが発生します。

例:

>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration

単なる観察:yは反復子オブジェクトになっているため、y = iter(x)は正確にはy = [1,2,3,4]ではありません。おそらく、コメントを追加して、リストではなくイテレータオブジェクトであることを明確にするか、表現を変更する必要があります。
coelhudo

-6

Pythonでは、すべてがオブジェクトです。オブジェクトが反復可能であるとは、オブジェクトをコレクションとしてステップ実行(つまり反復)できることを意味します。

たとえば、配列は反復可能です。forループでそれらをステップ実行し、インデックス0からインデックスnに移動できます。nは、配列オブジェクトの長さから1を引いたものです。

辞書(キー/値のペア、連想配列とも呼ばれます)も反復可能です。あなたは彼らの鍵を踏むことができます。

明らかに、コレクションではないオブジェクトは反復可能ではありません。たとえば、boolオブジェクトにはTrueまたはFalseの1つの値しかありません。反復可能ではありません(反復可能オブジェクトであるとは意味がありません)。

続きを読む。http://www.lepus.org.uk/ref/companion/Iterator.xml


6
コレクションではないオブジェクトは反復可能ではないため、一般的には正しくありません。いくつかの例をあげると、ジェネレータは反復可能ですがコレクションではありません。iter()標準のコレクション型を呼び出すことによって作成された反復子オブジェクトは反復可能ですが、それ自体はコレクションではありません。
Mark Amery 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.