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 forpę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, forpętla. Wygląda na pracę dla iteratora ... Zdobądźmy ją. ... Jest ten objfacet, 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 objudał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 _iprzekazany przez niego objnie był aż tak błyszczący, ale objsam 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 forpętli. Ta forpętla przede wszystkim potrzebuje __iter__()
(która zwraca coś next()).
Oczywiście fornie 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” _itak 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.AsyncIteratortesty__aiter__i__anext__metody. To jest nowy dodatek w wersji 3.6.