generator
;Тип generator
(генератор) похож на тип iterator
(итератор), но тип generator
не хранит значения последовательности в памяти, а генерирует/вычисляет результат на лету - в ходе каждого вызова, тем самым экономит память и вычислительные ресурсы.
Функция считается генератором, если:
yield
.generator
, но не начнет выполнение.__iter__()
и __next__()
реализуются автоматически.StopIteration
.Важно! Так как генератор - это "улучшенный" итератор, следовательно на тип
generator
распространяются такие же ограничения как и тип типiterator
.
yield
.Выражение yield
предоставляют удобный способ реализации протокола итератора, который технически, представляет из себя объект генератора. Это выражение используется в теле функции и приводит к тому, что функция становится генератором. Выражение yield
используется примерно как return
, отличие в том, что функция возвращает генератор.
Функции-генераторы так же могут включать инструкцию return
, которая завершает генерацию значений, возбуждая исключение StopIteration
после выполнения обычного выхода из функции. С точки зрения вызывающей программы, метод generator.__next__()
генератора возобновляет выполнение функции, пока она не встретит следующую инструкцию yield
или пока не возбудит исключение StopIteration
.
Выполнение начинается при вызове одного из методов генератора. В это время выполнение переходит к первому выражению yield
, где он снова приостанавливается, возвращая значение expression_list
, объекту, вызвавшему генератор. Под приостановкой, подразумевается сохранение всех локальных состояний, включая текущие привязки локальных переменных, указатель инструкции, внутренний стек вычислений и состояние любой обработки исключений.
Когда выполнение возобновляется вызовом одного из методов генератора, то он может действовать точно так же, как если бы выражение yield
было просто другим внешним вызовом. Значение выражения yield
после возобновления зависит от метода, который возобновил выполнение. Если используется метод generator.__next__()
(обычно через for ... in
или функцию next()
), то результат отсутствует. В противном случае, если используется метод generator.send()
, то результатом будет значение, переданное этому методу.
Выражения yield
допускаются в любом месте конструкции try ... expect
. Если генератор не возобновляется до его завершения (при достижении нулевого числа ссылок или при сборе мусора), то вызывается метод generator.close()
генератора, позволяющий инструкции finally
в конструкции try ... expect
, выполнить любой завершающий код.
def echo(value=None): print("next() вызвали в первый раз - началось выполнение.") try: while True: try: value = (yield value) # Приостановка. Все локальное состояние # сохраняется до следующего вызова except Exception as e: value = e finally: print("Вызван метод close(), не забудьте очистить память.") generator = echo(1) print(next(generator)) # next() вызвали в первый раз - началось выполнение. # 1 print(next(generator)) # None print(generator.send(2)) # 2 print(generator.throw(TypeError, "- Error -")) # - Error - generator.close() # Вызван метод close(), не забудьте очистить память.
yield from <expression>
.Если в генераторе используется выражение yield from <expression>
, то он обрабатывает предоставленное выражение <expression>
как другой итератор. Все значения, выданные этим под-итератором, передаются непосредственно вызывающей стороне текущего генератора.
Если выражение <expression>
это генератор, то любые значения, передаваемые с помощью метода generator.send()
и любые исключения, передаваемые с помощью метода generator.throw()
, передаются базовому генератору в соответствующие методы. Если соответствующие методы не определены, то generator.send()
вызовет исключение AttributeError
или TypeError
, в то время как generator.throw()
просто немедленно вызовет переданное исключение.
Когда базовый итератор завершен, то атрибут value
возвращает исключения StopIteration
, которое становится значением выражения yield
. Оно может быть установлено либо явно при появлении StopIteration
, либо автоматически, когда под-итератор <expression>
является генератором и возвращает значение.
Дополнительно смотрите раздел "Выражение-генератора yield from <expression>
".
generator
.Обратите внимание, что вызов любого из методов генератора, когда генератор уже выполняется, вызывает исключение ValueError
.
generator.__next__()
:Запускает выполнение функции генератора или возобновляет его при последнем выполненном выражении yield
. Когда функция генератора возобновляется с помощью метода __ next__ ()
, текущее выражение yield
всегда возвращает как None
. Затем выполнение продолжается до следующего выражения yield
, где генератор снова приостанавливается, а значение expression_list
возвращается объекту вызвавшему __next__()
. Если генератор завершает работу без получения другого значения, возникает исключение StopIteration
.
Этот метод обычно вызывается неявно, например, с помощью for ... in
цикла или встроенной next()
функции.
generator.send(value)
:Метод возобновляет выполнение и “отправляет " значение в функцию генератора. Аргумент value
становится результатом текущего выражения yield
. Метод generator.send()
возвращает следующее значение, полученное генератором, или вызывает StopIteration
, если генератор завершает работу без получения другого значения. Когда generator.send()
вызывается для запуска генератора, он должен быть вызван с аргументом None
, поскольку нет выражения yield
, которое могло бы получить значение.
Метод generator.send(value)
может использоваться, например, чтобы реализовать генератор, который можно будет завершать из вызывающей программы или переустанавливать в нем текущую позицию в последовательности результатов.
generator.throw(type[, value[, traceback]])
:Метод вызывает исключение типа type
в точке, где генератор был приостановлен и возвращает следующее значение, полученное функцией генератора. Если генератор завершает работу без получения другого значения, возникает исключение StopIteration
. Если функция генератора не ловит переданное исключение или вызывает другое исключение, то это исключение распространяется на вызывающий объект.
generator.close()
:Метод вызывает исключение GeneratorExit
в точке, где функция генератора была приостановлена. Если функция генератора затем завершает работу корректно, уже закрыта или вызывает GeneratorExit
(не улавливая исключение), close возвращается к вызывающему объекту. Если генератор выдает значение, то возникает ошибка RuntimeError
. Если генератор вызывает любое другое исключение, оно передается вызывающему объекту. Метод generator.close()
ничего не делает, если генератор уже вышел из-за исключения или нормального выхода..
Понимание того, как работают итераторы и генераторы в языках программирования, это один из первых шагов к освоению последовательной обработки гигантских потоков данных. Трейдинг и технический анализ, это вещи, на которых многие делают целое состояние.