В чем разница между итераторами и генераторами? Несколько примеров того, когда вы будете использовать каждый случай, были бы полезны.
iterator
это более общая концепция: любой объект, класс которого имеет next
метод ( __next__
в Python 3) и __iter__
метод, который имеет return self
.
Каждый генератор является итератором, но не наоборот. Генератор создается путем вызова функции, которая имеет одно или несколько yield
выражений ( yield
операторов в Python 2.5 и более ранних версиях) и является объектом, который соответствует определению предыдущего абзаца iterator
.
Вы можете захотеть использовать пользовательский итератор, а не генератор, когда вам нужен класс с несколько сложным поведением, поддерживающим состояние, или вы хотите представить другие методы помимо next
(и __iter__
и __init__
). Чаще всего достаточно генератора (иногда, для достаточно простых нужд, выражения генератора ), и его проще кодировать, потому что поддержание состояния (в разумных пределах) в основном «выполняется для вас», когда кадр приостанавливается и возобновляется.
Например, такой генератор, как:
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
или эквивалентный генератор выражения (genexp)
generator = (i*i for i in range(a, b))
потребовалось бы больше кода для сборки в качестве пользовательского итератора:
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self): return self
def next(self): # __next__ in Python 3
if self.start >= self.stop:
raise StopIteration
current = self.start * self.start
self.start += 1
return current
iterator = Squares(a, b)
Но, конечно, с классом Squares
вы можете легко предложить дополнительные методы, т.е.
def current(self):
return self.start
если у вас есть какая-либо реальная потребность в такой дополнительной функциональности в вашем приложении.
for ... in ...:
, переданная функции, либо вы будете вызыватьiter.next()
for..in
синтаксис. Может быть, я что-то упустил, но это было некоторое время назад, я не помню, решил ли я. Спасибо!Итак, итераторы - это объекты, у которых есть метод
__iter__
и__next__
(next
в Python 2). Генераторы предоставляют простой встроенный способ создания экземпляров итераторов.Функция с yield в ней по-прежнему является функцией, которая при вызове возвращает экземпляр объекта-генератора:
Выражение генератора также возвращает генератор:
Для более глубокого изложения и примеров, продолжайте читать.
Генератор - это итератор
В частности, генератор является подтипом итератора.
Мы можем создать генератор несколькими способами. Очень распространенный и простой способ сделать это с помощью функции.
В частности, функция с yield в ней является функцией, которая при вызове возвращает генератор:
И генератор, опять же, является Итератором:
Итератор - это итеративный
Итератор итеративный,
для чего требуется
__iter__
метод, который возвращает Iterator:Некоторыми примерами итераций являются встроенные кортежи, списки, словари, наборы, замороженные наборы, строки, байтовые строки, байтовые массивы, диапазоны и представления памяти:
Итераторы требуют
next
или__next__
методаВ Python 2:
И в Python 3:
Мы можем получить итераторы из встроенных объектов (или пользовательских объектов) с помощью
iter
функции:__iter__
Метод вызывается при попытке использовать объект с для петли. Затем__next__
вызывается метод объекта итератора, чтобы вывести каждый элемент в цикл. Итератор повышается,StopIteration
когда вы исчерпали его, и он не может быть повторно использован в этой точке.Из документации
Из разделе Типы генератора в разделе Типы Итератор Встроенные типы документации :
(Акцент добавлен.)
Из этого мы узнаем, что Генераторы - это (удобный) тип Итератора.
Примеры объектов-итераторов
Вы можете создать объект, который реализует протокол Iterator, создав или расширив свой собственный объект.
Но для этого проще просто использовать генератор:
Или, может быть, проще, выражение генератора (работает аналогично списку пониманий):
Все они могут быть использованы одинаково:
Вывод
Вы можете использовать протокол Iterator напрямую, когда вам нужно расширить объект Python как объект, который можно перебирать.
Тем не менее, в подавляющем большинстве случаев лучше всего использовать
yield
для определения функции, которая возвращает итератор генератора или учитывает выражения генератора.Наконец, обратите внимание, что генераторы обеспечивают еще больше функциональности в качестве сопрограмм. Я объясню Генераторам вместе с
yield
утверждением подробно мой ответ на вопрос «Что делает ключевое слово yield»?источник
итераторы:
Итераторы - это объекты, которые используют
next()
метод для получения следующего значения последовательности.Генераторы:
Генератор - это функция, которая создает или возвращает последовательность значений с использованием
yield
метода.Каждый
next()
вызов метода для объекта генератора (например,f
как в примере ниже), возвращаемый функцией генератора (дляfoo()
функции ex в примере ниже), генерирует следующее значение в последовательности.Когда вызывается функция генератора, она возвращает объект генератора, даже не начав выполнение функции. Когда
next()
метод вызывается в первый раз, функция начинает выполняться, пока не достигнет оператора yield, который возвращает полученное значение. Выход отслеживает, т.е. запоминает последнее выполнение. И второйnext()
звонок продолжается с предыдущего значения.В следующем примере демонстрируется взаимодействие между yield и вызовом метода next для объекта генератора.
источник
Добавление ответа, потому что ни один из существующих ответов конкретно не устраняет путаницу в официальной литературе.
Функции генератора - это обычные функции, определенные
yield
вместоreturn
. При вызове функция генератора возвращает объект генератора , который является своего рода итератором - у него естьnext()
метод. При вызовеnext()
возвращается следующее значение, полученное функцией генератора.Либо функцию, либо объект можно назвать «генератором», в зависимости от того, какой исходный документ Python вы прочитали. Словарь Python говорит функцию генератора, в то время как Python вики означает объекты генератора. Учебник Python замечательно удается подразумевать как использования в пространстве трех предложений:
Первые два предложения идентифицируют генераторы с функциями генератора, а третье предложение идентифицирует их с объектами генератора.
Несмотря на всю эту путаницу, можно найти ссылку на язык Python для ясного и окончательного слова:
Таким образом, в формальном и точном использовании, термин «генератор» означает объект генератора, а не функцию генератора.
Приведенные выше ссылки относятся к Python 2, но ссылка на язык Python 3 говорит о том же. Тем не менее, глоссарий Python 3 утверждает, что
источник
У всех есть действительно хороший и подробный ответ с примерами, и я действительно ценю это. Я просто хотел дать несколько коротких ответов для людей, которые еще не совсем поняли концептуально:
Если вы создаете свой собственный итератор, он немного вовлечен - вы должны создать класс и, по крайней мере, реализовать методы iter и next. Но что делать, если вы не хотите проходить через это и хотите быстро создать итератор. К счастью, Python предоставляет краткий способ определения итератора. Все, что вам нужно сделать, это определить функцию по крайней мере с одним вызовом yield, и теперь, когда вы вызываете эту функцию, она возвращает « что-то », которое будет действовать как итератор (вы можете вызвать метод next и использовать его в цикле for). Это что-то имеет имя в Python под названием Generator
Надеюсь, это прояснит немного.
источник
Предыдущие ответы пропустили это дополнение: у генератора есть
close
метод, а у типичных итераторов - нет. Вclose
метод вызываетStopIteration
исключение в генераторе, который может быть пойман вfinally
статье в этом итератора, чтобы получить возможность запускать некоторые очистки. Эта абстракция делает его наиболее пригодным для больших итераторов. Можно закрыть генератор, как можно закрыть файл, не беспокоясь о том, что под ним.Тем не менее, мой личный ответ на первый вопрос будет таким: итеративный
__iter__
метод имеет только метод, типичные итераторы имеют__next__
только метод, генераторы имеют как__iter__
и, так__next__
и дополнительныйclose
.На второй вопрос мой личный ответ будет таким: в общедоступном интерфейсе я склоняюсь к тому, чтобы отдавать предпочтение генераторам, так как он более устойчив:
close
метод с большей совместимостьюyield from
. Локально, я могу использовать итераторы, но только если это плоская и простая структура (итераторы не сочиняются легко) и если есть основания полагать, что последовательность довольно короткая, особенно если ее можно остановить до того, как она достигнет конца. Я склонен рассматривать итераторы как низкоуровневый примитив, за исключением литералов.Для вопросов управления потоком генераторы являются столь же важной концепцией, как и обещания: и абстрактные, и составные.
источник
__iter__
метод, почему итератор может иметь__next__
только? Если они должны быть итеративными, я бы ожидал, что они__iter__
тоже будут.__iter__
итераторов on для возврата итератора, который требует толькоnext
метода (__next__
в Python3). Пожалуйста, не путайте стандарты (для утиной типизации) с их реализацией (как это реализовал конкретный интерпретатор Python). Это немного похоже на путаницу между функциями генератора (определение) и объектами генератора (реализация). ;)Функция Generator похожа на обычную функцию в Python, но содержит один или несколько
yield
операторов. Функции генератора - отличный инструмент для максимально простого создания объектов Iterator . Объект Iterator, возвращаемый функцией генератора, также называется объектом Generator или Генератором .В этом примере я создал функцию Generator, которая возвращает объект Generator
<generator object fib at 0x01342480>
. Как и другие итераторы, объекты Generator могут использоваться вfor
цикле или со встроенной функцией,next()
которая возвращает следующее значение из генератора.Таким образом, функция генератора - это самый простой способ создать объект Iterator.
Каждый объект генератора является итератором, но не наоборот. Пользовательский объект итератора может быть создан, если его класс реализует
__iter__
и__next__
метод (также называемый протоколом итератора).Однако гораздо проще использовать функцию генераторов для создания итераторов, поскольку они упрощают их создание, но пользовательский итератор дает вам больше свободы, и вы также можете реализовывать другие методы в соответствии с вашими требованиями, как показано в следующем примере.
источник
Примеры от Неда Батчелдера настоятельно рекомендуются для итераторов и генераторов.
Метод без генераторов, которые делают что-то с четными числами
в то время как с помощью генератора
return
заявлениеВызов
evens
метода (генератора) как обычноИтератор
и эта закладка не имеет ничего общего, кроме как двигаться
next
Чтобы использовать генератор ... нам нужна функция
Чтобы использовать Iterator ... нам нужно
next
иiter
Как уже было сказано:
Вся выгода от Iterator:
источник
Вы можете сравнить оба подхода для одних и тех же данных:
Кроме того, если вы проверите объем памяти, генератор занимает гораздо меньше памяти, так как ему не нужно хранить все значения в памяти одновременно.
источник
Я пишу специально для новичков в Python очень простым способом, хотя в глубине души Python делает очень много вещей.
Начнем с самого простого:
Рассмотрим список,
Давайте напишем эквивалентную функцию:
о / п из
print(l): [1,2,3]
& о / п оprint(f()) : [1,2,3]
Давайте сделаем список l итерируемым: в python список всегда итерируем, что означает, что вы можете применять итератор в любое время.
Давайте применим итератор в списке:
Давайте сделаем функцию итеративной, т.е. напишем эквивалентную функцию генератора. В Python, как только вы введете ключевое слово
yield
; она становится функцией генератора, и итератор будет применяться неявно.Примечание: каждый генератор всегда итеративен с примененным неявным итератором, и здесь неявный итератор - суть, поэтому функция генератора будет:
Так что если вы заметили, как только вы сделали функцию fa генератора, она уже iter (f)
Сейчас же,
Это как бы вы приводите int к int (x), который уже является int, и он останется int (x).
Например, о / п из:
является
Никогда не забывайте, что это Python, а не C или C ++
Отсюда вывод из приведенного выше объяснения:
источник