Что такое итератор, итерация и итерация? - PullRequest
390 голосов
/ 27 марта 2012

Какое самое основное определение «итерируемого», «итератора» и «итерации» в Python?

Я прочитал несколько определений, но я не могу определить точное значение, поскольку оно все еще не будет

Может кто-нибудь помочь мне с 3 определениями в терминах непрофессионала?

Ответы [ 12 ]

461 голосов
/ 27 марта 2012

Итерация - это общий термин для обозначения каждого предмета чего-либо один за другим.Каждый раз, когда вы используете цикл, явный или неявный, для обхода группы элементов, то есть итерации.

В Python iterable и iterator имеют определенные значения.

Итерация - это объект, у которого есть метод __iter__, который возвращает итератор , или который определяет метод __getitem__, который может принимать последовательные индексы, начиная сс нуля (и поднимает IndexError, когда индексы больше не действительны).Таким образом, iterable - это объект, из которого вы можете получить iterator .

iterator - это объект с next (Python2) или __next__ (Python 3) метод.

Всякий раз, когда вы используете цикл for, или map, или понимание списка, и т. Д. В Python, метод next вызывается автоматически для получения каждого элемента из итератора * 1034.*, таким образом, проходя процесс итерации .

Хорошим местом для начала обучения будет раздел итераторов учебника и раздел типов итераторовстраницы стандартных типов .После того, как вы поймете основы, попробуйте раздел итераторов Функционального программирования HOWTO .

298 голосов
/ 27 марта 2012

Вот объяснение, которое я использую в преподавании классов Python:

ITERABLE - это:

  • все, что может быть зациклено (т. Е. Вы можете зациклить строку или файл) или
  • все, что может появиться в правой части цикла for: for x in iterable: ... или
  • все, что вы можете вызвать с помощью iter(), которое вернет Итератор: iter(obj) или
  • объект, который определяет __iter__, который возвращает свежий ITERATOR, или он может иметь метод __getitem__, подходящий для индексированного поиска.

Итератор - это объект:

  • с состоянием, которое запоминает, где оно находится во время итерации,
  • методом __next__, который:
    • возвращает следующее значение в итерации
    • обновляет состояние, чтобы указывать на следующее значение
    • сигнализирует, когда это сделано путем повышения StopIteration
  • и это само итеративно (это означает, что у него есть метод __iter__, который возвращает self).

Примечания:

  • Метод __next__ в Python 3 пишется next в Python 2 и
  • Встроенная функция 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
93 голосов
/ 11 сентября 2013

Приведенные выше ответы великолепны, но, как большинство из того, что я видел, не подчеркивайте различие , достаточное для таких людей, как я.

Кроме того, люди, как правило, получают «слишком Pythonic», помещая такие определения, как «X - это объект, у которого есть __foo__() метод» ранее. Такие определения являются правильными - они основаны на философии типизации утки, но при попытках понять концепцию в ее простоте основное внимание уделяется методам.

Итак, я добавляю свою версию.


На естественном языке,

  • итерация - это процесс принятия по одному элементу за раз в ряд элементов.

В Python,

  • итерируемый - это итеративный объект, который проще говоря означает, что это может быть использовано в итерации, например, с петлей for. Как? Используя итератор . Я объясню ниже.

  • ... тогда как итератор - это объект, который определяет , как на самом деле итерация - в частности , что является следующим элементом. Вот почему это должно иметь next() метод.

Итераторы сами по себе также итерируемы, с той разницей, что их метод __iter__() возвращает один и тот же объект (self), независимо от того, были ли его элементы использованы предыдущими вызовами next().


Так что же думает интерпретатор Python, когда видит выражение for x in obj:?

Смотри, петля for. Похоже, работа для итератора ... Давайте возьмем. ... Вот этот obj парень, так что давайте спросим его.

"Мистер. obj, у вас есть итератор?" (... звонит iter(obj), который звонит obj.__iter__(), который радостно раздает новый блестящий итератор _i.)

Хорошо, это было легко ... Давайте начнем итерацию. (x = _i.next() ... x = _i.next() ...)

Поскольку г-н obj успешно прошел этот тест (имея определенный метод, возвращающий действительный итератор), мы вознаграждаем его прилагательным: теперь вы можете называть его «итеративный г-н obj».

Однако в простых случаях вам не выгодно иметь итератор и итерацию отдельно. Таким образом, вы определяете только один объект, который также является его собственным итератором. (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()

Однако существуют случаи, когда вы можете извлечь выгоду из отделения итератора от итерируемого, например, когда вы хотите иметь одну строку элементов, но больше «курсоров». Например, когда вы хотите работать с «текущими» и «предстоящими» элементами, вы можете иметь отдельные итераторы для обоих. Или несколько потоков, извлекаемых из огромного списка: у каждого может быть свой собственный итератор для обхода всех элементов. См. @ Raymond's и @ glglgl's ответов выше.

Представьте, что вы можете сделать:

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() может выдать StopItered, чтобы остановить итерацию. Не должны, тем не менее, он может повторяться вечно или использовать другие средства.

  • В вышеупомянутом «мыслительном процессе» _i на самом деле не существует. Я придумал это имя.

  • В Python 3.x есть небольшое изменение: next() метод (не встроенный) сейчас должен называться __next__(). Да, так должно было быть все время.

  • Вы также можете думать об этом так: итеративный имеет данные, итератор вытягивает следующий пункт

Отказ от ответственности: Я не являюсь разработчиком какого-либо интерпретатора Python, поэтому я действительно не знаю, что "думает" интерпретатор. Приведенные выше размышления являются лишь демонстрацией того, как я понимаю эту тему из других объяснений, экспериментов и реального опыта новичка в Python.

21 голосов
/ 27 марта 2012

Итерируемый - это объект, у которого есть метод __iter__().Возможно, он может повторяться несколько раз, например list() s и tuple() s.

Итератор - это объект, который выполняет итерацию.Он возвращается методом __iter__(), возвращает себя через собственный метод __iter__() и имеет метод next() (__next__() в 3.x).

Итерация - это процесс вызова this 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
9 голосов
/ 30 сентября 2015

Я не знаю, помогает ли это кому-нибудь, но мне всегда нравится визуализировать концепции в моей голове, чтобы лучше понять их. Так как у меня есть маленький сын, я визуализирую концепцию итерации / итератора с помощью кирпичиков и белой бумаги.

Предположим, мы в темной комнате и на полу у нас есть кирпичи для моего сына. Кирпичи разного размера, цвета, теперь не имеет значения. Предположим, у нас есть 5 таких кирпичей. Эти 5 кирпичей можно описать как объект - скажем, набор кирпичей . С этим набором кирпичей мы можем многое сделать - взять один, затем второй, а затем третий, поменять местами кирпичи, поставить первый кирпич выше второго. Мы можем сделать много разных вещей с ними. Поэтому этот набор кирпичей является повторяемым объектом или последовательность , поскольку мы можем пройти через каждый кирпич и что-то с ним сделать. Мы можем делать это только как мой маленький сын - мы можем играть с один кирпич за один раз . Итак, снова я представляю себе этот набор кирпичей, чтобы он был повторяемым .

Теперь помните, что мы в темной комнате. Или почти темно. Дело в том, что мы не ясно видим эти кирпичи, какого они цвета, какой формы и т. Д. Поэтому, даже если мы хотим что-то с ними сделать - ака перебрать их - мы на самом деле не знаем что и как, потому что слишком темно.

Что мы можем сделать, так это приблизиться к первому кирпичу - как элементу набора кирпичей - мы можем положить лист белой флуоресцентной бумаги, чтобы мы увидели, где находится первый кирпичный элемент. И каждый раз, когда мы берем кирпич из комплекта, мы заменяем белый лист бумаги следующим кирпичиком, чтобы увидеть его в темной комнате. Этот белый лист бумаги - не более чем итератор . Это также объект . Но объект, с которым мы можем работать и играть с элементами нашего итерируемого объекта - набор кирпичей.

Это, кстати, объясняет мою раннюю ошибку, когда я попробовал следующее в IDLE и получил ошибку типа:

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

Не знаю, поможет ли это, но это помогло мне. Если бы кто-то смог подтвердить / исправить визуализацию концепции, я был бы благодарен. Это помогло бы мне узнать больше.

7 голосов
/ 25 марта 2018

Вот моя шпаргалка:

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

Тест: Видите ли вы, как ...

  • каждый итератор является итеративным?
  • контейнерного объекта__iter__() метод может быть реализован как генератор?
  • итеративный метод плюс __next__ не обязательно является итератором?
4 голосов
/ 28 мая 2018

Итерируемый : - что-то итерируемое итеративно;такие как последовательности, такие как списки, строки и т. д. Также он имеет метод __getitem__ или метод __iter__.Теперь, если мы используем функцию iter() для этого объекта, мы получим итератор.

Итератор : - когда мы получаем объект итератора из функции iter();мы вызываем метод __next__() (в python3) или просто next() (в python2), чтобы получить элементы один за другим.Этот класс или экземпляр этого класса называется итератором.

Из документов: -

Использование итераторов пронизывает и объединяет Python.За кулисами оператор for вызывает iter() для объекта контейнера.Функция возвращает объект итератора, который определяет метод __next__(), который обращается к элементам в контейнере по одному.Когда элементов больше нет, __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
3 голосов
/ 19 июня 2017
iterable = [1, 2] 

iterator = iter(iterable)

print(iterator.__next__())   

print(iterator.__next__())   

так

  1. iterable - это объект , который может быть зациклен на . например список, строка, кортеж и т. д.

  2. с использованием функции iter нашего объекта iterable вернет объект итератора .

  3. теперь этот объект итератора имеет метод с именем __next__ (в Python 3 или просто next в Python 2), с помощью которого вы можете получить доступ к каждому элементу итерируемого.

так, ВЫВОД ВЫШЕГО КОДА БУДЕТ:

1

2

3 голосов
/ 27 марта 2012

Я не думаю, что вы можете сделать это намного проще, чем документация , однако я постараюсь:

  • Итерируемый - это то, чтоможет быть повторен более.На практике это обычно означает последовательность например что-то, что имеет начало и конец и какой-то способ пройти через все элементы в нем.
  • Выможет думать Итератор как вспомогательный псевдо-метод (или псевдоатрибут), который дает (или содержит) следующий (или первый) элемент в итерируемый .(На практике это просто объект, который определяет метод next())

  • Итерация , вероятно, лучше всего объясняется определением Merriam-Webster слово :

b: повторение последовательности компьютерных инструкций указанное количество раз или до выполнения условия - сравните рекурсию

1 голос
/ 06 сентября 2018

Итерируемые имеют метод __iter__, который каждый раз создает новый итератор.

Итераторы реализуют метод __next__, который возвращает отдельные элементы, и метод __iter__, который возвращает self.

Следовательно, итераторы также итерируемы, но итераторы не являются итераторами.

Лучано Рамальо, Свободный Питон.

...