Die obigen Antworten sind großartig, aber wie das meiste, was ich gesehen habe, betonen Sie die Unterscheidung nicht genug für Leute wie mich.
Außerdem neigen Menschen dazu, "zu pythonisch" zu werden, indem sie zuvor Definitionen wie "X ist ein Objekt mit __foo__()
Methode" setzen. Solche Definitionen sind korrekt - sie basieren auf der Philosophie der Ententypisierung, aber der Fokus auf Methoden liegt tendenziell dazwischen, wenn versucht wird, das Konzept in seiner Einfachheit zu verstehen.
Also füge ich meine Version hinzu.
In natürlicher Sprache
- Bei der Iteration wird jeweils ein Element in einer Reihe von Elementen aufgenommen.
In Python
iterable ist ein Objekt, das iterable ist, was einfach ausgedrückt bedeutet, dass es in der Iteration verwendet werden kann, z for
. B. mit einer Schleife. Wie? Mit dem Iterator . Ich werde unten erklären.
... während der Iterator ein Objekt ist, das definiert, wie die Iteration tatsächlich durchgeführt wird - insbesondere, was das nächste Element ist. Deshalb muss es
next()
Methode haben.
Iteratoren sind selbst auch iterierbar, mit dem Unterschied, dass ihre __iter__()
Methode dasselbe Objekt ( self
) zurückgibt , unabhängig davon, ob ihre Elemente von früheren Aufrufen an verbraucht wurden oder nicht next()
.
Was denkt der Python-Interpreter, wenn er eine for x in obj:
Aussage sieht ?
Schau, eine for
Schleife. Sieht aus wie ein Job für einen Iterator ... Lassen Sie uns einen bekommen. ... Da ist dieser obj
Typ, also fragen wir ihn.
"Mr. obj
, haben Sie Ihren Iterator?" (... ruft an iter(obj)
, was anruft
obj.__iter__()
, was glücklich einen glänzenden neuen Iterator verteilt _i
.)
OK, das war einfach ... Dann fangen wir an zu iterieren. ( x = _i.next()
... x = _i.next()
...)
Da Mr. obj
diesen Test erfolgreich abgeschlossen hat (indem eine bestimmte Methode einen gültigen Iterator zurückgibt), belohnen wir ihn mit einem Adjektiv: Sie können ihn jetzt "iterable Mr. obj
" nennen.
In einfachen Fällen profitieren Sie jedoch normalerweise nicht davon, dass Iterator und Iterator separat verfügbar sind. Sie definieren also nur ein Objekt, das auch ein eigener Iterator ist. (Python ist es eigentlich egal, dass _i
das, was von obj
ausgegeben wurde, nicht so glänzend war, sondern nur das obj
selbst.)
Aus diesem Grund können Sie in den meisten Beispielen, die ich gesehen habe (und was mich immer wieder verwirrt hat), Folgendes sehen:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
anstatt
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
Es gibt jedoch Fälle, in denen Sie davon profitieren können, dass der Iterator vom iterablen getrennt wird, z. B. wenn Sie eine Reihe von Elementen, aber mehr "Cursor" haben möchten. Wenn Sie beispielsweise mit "aktuellen" und "bevorstehenden" Elementen arbeiten möchten, können Sie für beide separate Iteratoren verwenden. Oder mehrere Threads, die aus einer riesigen Liste gezogen werden: Jeder kann seinen eigenen Iterator haben, um alle Elemente zu durchlaufen. Siehe die Antworten von @ Raymond und @ glglgl 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()
Anmerkungen:
Ich wiederhole noch einmal: Iterator ist nicht iterierbar . Der Iterator kann nicht als "Quelle" in einer for
Schleife verwendet werden. Was die for
Schleife hauptsächlich benötigt, ist __iter__()
(das gibt etwas mit zurück next()
).
Natürlich for
ist dies nicht die einzige Iterationsschleife, daher gilt das oben Gesagte auch für einige andere Konstrukte ( while
...).
Iteratoren next()
können StopIteration auslösen, um die Iteration zu stoppen. Muss aber nicht, es kann für immer iterieren oder andere Mittel verwenden.
Im obigen "Denkprozess" _i
existiert nicht wirklich. Ich habe diesen Namen erfunden.
Es gibt eine kleine Änderung in Python 3.x: Die next()
Methode (nicht die eingebaute) muss jetzt aufgerufen werden __next__()
. Ja, das hätte die ganze Zeit so sein sollen.
Sie können sich das auch so vorstellen: iterable hat die Daten, iterator zieht das nächste Element
Haftungsausschluss: Ich bin kein Entwickler eines Python-Interpreters, daher weiß ich nicht genau, was der Interpreter "denkt". Die obigen Überlegungen zeigen lediglich, wie ich das Thema anhand anderer Erklärungen, Experimente und realer Erfahrungen eines Python-Neulings verstehe.
collections.abc.AsyncIterator
Tests für__aiter__
und__anext__
Methoden. Dies ist eine neue Ergänzung in 3.6.