Powyższe odpowiedzi są świetne, ale jak większość tego, co widziałem, nie podkreślaj wystarczająco rozróżnienia dla ludzi takich jak ja.
Ponadto ludzie mają skłonność do „zbyt Pythonic”, umieszczając definicje takie jak „X to obiekt, który ma __foo__()
metodę” wcześniej. Takie definicje są poprawne - opierają się na filozofii pisania kaczego, ale skupienie się na metodach zwykle występuje pomiędzy próbą zrozumienia pojęcia w jego prostocie.
Więc dodaję swoją wersję.
W języku naturalnym
- iteracja to proces pobierania jednego elementu na raz z rzędu elementów.
W Pythonie
iterowalny to obiekt, który jest, cóż, iterowalny, co po prostu oznacza, że można go użyć w iteracji, np. z for
pętlą. W jaki sposób? Za pomocą iteratora . Wyjaśnię poniżej.
... podczas gdy iterator jest obiektem, który definiuje sposób wykonywania iteracji - w szczególności jaki jest następny element. Dlatego musi mieć
next()
metodę.
Iteratory również są iterowalne, z tą różnicą, że ich __iter__()
metoda zwraca ten sam obiekt ( self
), niezależnie od tego, czy jego elementy zostały wykorzystane przez poprzednie wywołania do next()
.
Co myśli interpreter Pythona, gdy widzi for x in obj:
oświadczenie?
Spójrz, for
pętla. Wygląda na pracę dla iteratora ... Zdobądźmy ją. ... Jest ten obj
facet, więc zapytajmy go.
„Panie obj
, masz swój iterator?” (... wzywa iter(obj)
, który wzywa
obj.__iter__()
, który szczęśliwie rozdaje nowy błyszczący iterator _i
).
OK, to było łatwe ... Zacznijmy od iteracji. ( x = _i.next()
... x = _i.next()
...)
Ponieważ Panowi obj
udało się w tym teście (mając pewną metodę zwracającą prawidłowy iterator), nagradzamy go przymiotnikiem: możesz teraz nazwać go „iterowalnym Panem obj
”.
Jednak w prostych przypadkach zwykle nie korzysta się z iteratora i iteracji oddzielnie. Definiujesz więc tylko jeden obiekt, który jest także własnym iteratorem. (Python tak naprawdę nie przejmuje się tym, że _i
przekazany przez niego obj
nie był aż tak błyszczący, ale obj
sam w sobie).
Oto dlaczego w większości przykładów, które widziałem (i co ciągle mnie myliło), możesz zobaczyć:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
zamiast
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
Są jednak przypadki, w których możesz oddzielić iterator od iterowalnego, na przykład gdy chcesz mieć jeden wiersz elementów, ale więcej „kursorów”. Na przykład, jeśli chcesz pracować z elementami „bieżącymi” i „nadchodzącymi”, możesz mieć osobne iteratory dla obu. Lub wiele wątków wyciąganych z ogromnej listy: każdy może mieć swój iterator do przechodzenia między wszystkimi elementami. Zobacz odpowiedzi @ Raymond i @ glglgl powyżej.
Wyobraź sobie, co możesz zrobić:
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()
Uwagi:
Powtórzę jeszcze raz: iterator nie jest powtarzalny . Iteratora nie można używać jako „źródła” w for
pętli. Ta for
pętla przede wszystkim potrzebuje __iter__()
(która zwraca coś next()
).
Oczywiście for
nie jest to jedyna pętla iteracyjna, więc powyższe dotyczy również niektórych innych konstrukcji ( while
...).
Iterator next()
może rzucić StopIteration, aby zatrzymać iterację. Nie musi jednak iterować wiecznie lub używać innych środków.
W powyższym „procesie myślowym” _i
tak naprawdę nie istnieje. Wymyśliłem to imię.
W Pythonie 3.x wprowadzono niewielką zmianę: next()
należy wywołać metodę (nie wbudowaną) __next__()
. Tak, tak powinno być przez cały czas.
Możesz również pomyśleć o tym w ten sposób: iterowalny ma dane, iterator pobiera następny element
Uwaga: Nie jestem programistą żadnego interpretera języka Python, więc tak naprawdę nie wiem, co interpreter „myśli”. Rozważania powyżej są jedynie demonstracją tego, jak rozumiem ten temat na podstawie innych wyjaśnień, eksperymentów i rzeczywistych doświadczeń początkującego Pythona.
collections.abc.AsyncIterator
testy__aiter__
i__anext__
metody. To jest nowy dodatek w wersji 3.6.