569 Stimmen

Was sind Iterator, Iterable und Iteration?

Was sind "Iterable", "Iterator" und "Iteration" in Python? Wie sind sie definiert?

657voto

agf Punkte 159286

Iteration ist ein allgemeiner Begriff für die Entnahme eines jeden Teils von etwas, eines nach dem anderen. Jedes Mal, wenn Sie eine explizite oder implizite Schleife verwenden, um eine Gruppe von Elementen zu durchlaufen, ist das eine Iteration.

In Python, iterierbar y Iterator haben bestimmte Bedeutungen.

Eine iterierbar ist ein Objekt, das eine __iter__ Methode, die eine Iterator oder die eine __getitem__ Methode, die sequentielle Indizes von Null an annehmen kann (und eine IndexError wenn die Indizes nicht mehr gültig sind). Also eine iterierbar ist ein Objekt, mit dem Sie eine Iterator von.

Eine Iterator ist ein Objekt mit einer next (Python 2) oder __next__ (Python 3) Methode.

Wann immer Sie eine for Schleife, oder map oder ein Listenverständnis, usw. in Python, die next Methode wird automatisch aufgerufen, um jedes Element aus der Iterator und durchläuft somit den Prozess der Iteration .

Ein guter Ort, um mit dem Lernen zu beginnen, ist die Abschnitt Iteratoren des Tutorials y el Iterator-Typen auf der Seite mit den Standardtypen . Nachdem Sie die Grundlagen verstanden haben, versuchen Sie die Iteratoren im Abschnitt Funktionale Programmierung des HOWTO .

412voto

Raymond Hettinger Punkte 197261

Hier ist die Erklärung, die ich im Python-Unterricht verwende:

Ein ITERABLE ist:

  • alles, was in einer Schleife durchlaufen werden kann (z. B. eine Zeichenkette oder eine Datei) oder
  • alles, was auf der rechten Seite einer for-Schleife erscheinen kann: for x in iterable: ... o
  • alles, was Sie aufrufen können mit iter() die einen ITERATOR zurückgibt: iter(obj) o
  • ein Objekt, das definiert __iter__ die einen neuen ITERATOR zurückgibt, oder es kann eine __getitem__ Methode, die für die indizierte Suche geeignet ist.

Ein ITERATOR ist ein Objekt:

  • mit einem Zustand, der sich merkt, wo er sich während der Iteration befindet,
  • mit einer __next__ Methode, die:
    • gibt den nächsten Wert in der Iteration zurück
    • aktualisiert den Status, so dass er auf den nächsten Wert zeigt
    • signalisiert, wenn dies geschieht, indem er StopIteration
  • und das ist selbstaufrufbar (was bedeutet, dass es eine __iter__ Methode, die Folgendes zurückgibt self ).

Notes :

  • Le site __next__ Methode in Python 3 wird buchstabiert next in Python 2, und
  • Die eingebaute Funktion next() ruft diese Methode für das übergebene Objekt auf.

Zum Beispiel:

>>> 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

127voto

Alois Mahdal Punkte 9963

Die obigen Antworten sind großartig, aber wie die meisten, die ich gesehen habe, betonen sie nicht die Auszeichnung genug für Leute wie mich.

Außerdem neigen die Leute dazu, "zu pythonisch" zu werden, indem sie Definitionen wie "X ist ein Objekt, das eine __foo__() Methode" vor. Solche Definitionen sind richtig - sie beruhen auf der Philosophie des "Duck-Typing", aber die Konzentration auf die Methoden gerät in den Hintergrund, wenn man versucht, das Konzept in seiner Einfachheit zu verstehen.

Ich füge also meine Version hinzu.


In natürlicher Sprache,

  • Iteration ist der Prozess, bei dem ein Element nach dem anderen in einer Reihe von Elementen genommen wird.

In Python,

  • iterierbar ist ein Objekt, das, nun ja, iterierbar ist, was einfach ausgedrückt bedeutet, dass es in einer Iteration verwendet werden kann, z.B. mit einer for Schleife. Und wie? Durch die Verwendung von Iterator . Ich werde es weiter unten erklären.

  • ... während Iterator ist ein Objekt, das definiert wie man es tatsächlich macht die Iteration - insbesondere was ist die nächste Element. Deshalb muss es Folgendes haben next() Methode.

Iteratoren sind selbst auch iterierbar, mit dem Unterschied, dass ihre __iter__() Methode gibt das gleiche Objekt zurück ( self ), unabhängig davon, ob seine Elemente durch frühere Aufrufe von next() .


Was denkt der Python-Interpreter also, wenn er sieht for x in obj: Aussage?

Schau, ein for Schleife. Sieht aus wie ein Job für einen Iterator... Besorgen wir uns einen. ... Da ist dies obj also fragen wir ihn.

"Mr. obj Haben Sie Ihren Iterator?" (... Anrufe iter(obj) , die die obj.__iter__() der fröhlich einen glänzenden neuen Iterator ausgibt _i .)

OK, das war einfach... Dann lasst uns mit der Iteration beginnen. ( x = _i.next() ... x = _i.next() ...)

Da Mr. obj diesen Test bestanden hat (indem eine bestimmte Methode einen gültigen Iterator zurückgibt), belohnen wir ihn mit einem Adjektiv: Sie können ihn jetzt "iterable Mr." nennen. obj ".

In einfachen Fällen ist es jedoch normalerweise nicht von Vorteil, Iterator und Iterable getrennt zu haben. Sie definieren also nur einer Objekt, das auch sein eigener Iterator ist. (Python kümmert sich nicht wirklich darum, dass _i ausgehändigt von obj war nicht besonders glänzend, sondern nur die obj selbst).

Das ist der Grund, warum ich in den meisten Beispielen, die ich gesehen habe (und was mich immer wieder verwirrt hat), zu sehen:

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

anstelle von

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

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

Es gibt jedoch Fälle, in denen es von Vorteil ist, wenn der Iterator von der Iterable getrennt ist, z. B. wenn Sie eine Reihe von Elementen, aber mehrere "Cursors" haben möchten. Wenn Sie zum Beispiel mit "aktuellen" und "zukünftigen" Elementen arbeiten wollen, können Sie für beide getrennte Iteratoren haben. Oder mehrere Threads, die auf eine große Liste zugreifen: jeder kann seinen eigenen Iterator haben, um alle Elemente zu durchlaufen. Siehe @Raymond's y @glglgl's Antworten oben.

Stellen Sie sich vor, was Sie tun könnten:

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()

Notes :

  • Ich wiederhole es noch einmal: Iterator ist nicht iterierbar . Iterator kann nicht verwendet werden als eine "Quelle" in for Schleife. Was for Schleife in erster Linie benötigt ist __iter__() (das etwas zurückgibt mit next() ).

  • Ja, natürlich, for ist nicht die einzige Iterationsschleife, daher gilt das oben Gesagte auch für einige andere Konstrukte ( while ...).

  • Iterator's next() kann StopIteration auslösen, um die Iteration zu beenden. Das muss nicht sein, aber es kann für immer iterieren oder andere Mittel verwenden.

  • In dem obigen "Gedankengang", _i nicht wirklich existiert. Ich habe mir diesen Namen ausgedacht.

  • Es gibt eine kleine Änderung in Python 3.x: next() Methode (nicht die eingebaute) jetzt muss aufgerufen werden __next__() . Ja, das hätte von Anfang an so sein sollen.

  • Man kann es sich auch so vorstellen: iterable hat die Daten, iterator zieht das nächste Element

Haftungsausschluss: Ich bin kein Entwickler eines Python-Interpreters, also weiß ich nicht wirklich, was der Interpreter "denkt". Die obigen Überlegungen sind lediglich eine Demonstration dessen, wie ich das Thema aus anderen Erklärungen, Experimenten und realen Erfahrungen eines Python-Neulings verstehe.

30voto

glglgl Punkte 84928

Ein iterable ist ein Objekt, das eine __iter__() Methode. Sie kann möglicherweise mehrmals wiederholt werden, z. B. list() s und tuple() s.

Ein Iterator ist ein Objekt, das eine Iteration durchführt. Er wird zurückgegeben von einem __iter__() Methode, gibt sich selbst über ihre eigene __iter__() Methode und hat eine next() Methode ( __next__() in 3.x).

Iteration ist der Prozess des Aufrufs dieser next() bzw. __next__() bis es aufsteigt StopIteration .

Beispiel:

>>> 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

20voto

AXO Punkte 6841

Hier ist mein Spickzettel:

 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 +-+

Quiz: Erkennst du, wie...

  1. jeder Iterator eine Iterable ist?
  2. eines Containerobjekts __iter__() Methode als Generator implementiert werden kann?
  3. eine Iterable, die eine __next__ Methode nicht unbedingt ein Iterator ist?

Antworten:

  1. Jeder Iterator muss eine __iter__ Methode. Unter __iter__ reicht aus, um eine Iterabilität zu sein. Daher ist jeder Iterator eine Iterable.

  2. Wenn __iter__ aufgerufen wird, sollte einen Iterator zurückgeben ( return <iterator> im obigen Diagramm). Der Aufruf eines Generators gibt einen Generator-Iterator zurück, der ein Typ von Iterator ist.

    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. Hier ist ein Beispiel:

    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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X