Python: Объяснение работы yield, итераторов и генераторов

Адаптивная, SEO подготовленная WordPress тема WordPress тема под вирусный контент и социальные сети

Для понимания что делает «yield», вы должны понимать что такое генераторы. Для понимания что такое генераторы — должны знать об итераторах и итерируемых объектах.

Итерируемые объекты (iterables)

Хочется назвать их неправильным, с точки зрения русского языка, словом «итерабельные» — т.е. те, по которым может происходить итерация. Но, правильнее будет назвать их «итерируемые», хотя лично меня это слово слегка путает.

Когда вы создаёте список (list) вы можете считывать его элементы по одному — это называется итерацией.

Lst — итерируемый объект (iterable). Когда вы используете списковые выражения (list comprehensions), вы создаёте список — итерируемый объект:

Любое объект который вы можете использовать в конструкции «for … in …» является итерирумым: списки, строки, файловые объекты и т.п.. Итерирумые объекты достаточно удобны потому что вы можете считывать из них столько данных, сколько вам необходимо, но при этом вы храните все значения последовательности в памяти и это не всегда приемлемо, особенно если вы имеете достаточно большие последовательности.

Генераторы

Генераторы — итерируемые объекты, но, в общем случае, вы можете их использовать только один раз. Это связано с тем, что они не хранят все значения в памяти, а генерируют значения «на лету» — по мере запроса:

Код выглядит почти так же, как и в предыдущем примере, только вместо квадратных скобочек («[<…>]») были использованы круглые («(<…>)»). Заметьте, что вы не можете выполнить цикл по generator во второй раз, поскольку ничего в памяти не хранится, попытка пройтись второй раз будет просто проигнорирована, т.к. generator выбросит при первом запросе на получение следующего значения StopIterationError, однако, вы это не заметите, если будете использовать цикл for, это исключение будет перехвачено и интерпретировано как конец цикла). Но вручную это можно проверить:

next — это метод для получения следующего значения генератора, если вы его используете не в цикле for.

Yield

Yield — это ключевое слово которое используется так же, как и слово return. Разница в том, что функция при этом начинает возвращать генератор вместо значения.

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

Для того чтобы до конца освоить оператор yield, вы должны знать, что когда вы вызываете функцию, в теле которой находится yield, выполнение этой функции не происходит. Вместо выполнения, функция вернёт объект-генератор. Выглядит это несколько странно на первый взгляд — функция вызвана, но код не выполнен, но, просто запомните этот факт. Код будет выполнятся при каждой итерации — будь то цикл «for <…> in <generator>» или вызов метода <generator>.next().

При первом исполнении кода тела функции код будет выполнен с начала и до первого встретившегося оператора yield. После этого будет возвращено первое значение и выполнение тела функции опять приостановлено. Запрос следующего значения у генератора во время итерации заставит код тела функции выполняться дальше (с предыдущего yield’а), пока не встретится следующий yield. Генератор считается «закончившимся» в случае если при очередном исполнении кода тела функции не было встречено ни одного оператора yield.

Управление исполнением генератора

В некоторых случаях такая логика может быть полезна, например, для контроля доступа к ресурсам.

Модуль стандартной библиотеки python — itertools

Модуль стандартной библиотеки python itertools содержит специальные функции для создания и работы с итераторами. С помощью этого модуля вы можете: клонировать итератор, объединить в цепочку несколько итераторов, сгруппировать значения вложенных списков в один, использовать версию map/zip на генераторах — imap/izip, на этом список не заканчивается.

Например, давайте вычислим все возможные варианты прихода лошадей в скачках (задача из комбинаторики — перестановки без повторов элементов):

Заметьте, что применение list к генератору вычислит все его значения и создаст из них список.

Понимание внутренней механики итерации

Итерация — это процесс подразумевающий итерируемые объекты («итерабельные», т.е. реализующие метод «__iter__()») и итераторы (реализующие метод «__next__()»). Итерируемые объекты — любые объекты, по которым может проходить итерация. Итераторы — объекты, которые позволяют вам производить итерацию по итерируемым объектам. Шла Саша по шоссе…

Более подробные объяснения будут рассмотрены в дальнейших статьях и переводах.

Понравилась статья? Поделиться с друзьями:
Комментариев: 6
  1. Ishayahu

    Версия 3.3

    >>> class Bank():
    crisis = False
    def create_atm(self):
    while not self.crisis:
    yield «$100»

    >>> bank=Bank()
    >>> atm=bank.create_atm()
    >>> bank.next()
    Traceback (most recent call last):
    File «», line 1, in
    bank.next()
    AttributeError: ‘Bank’ object has no attribute ‘next’
    >>> atm.next()
    Traceback (most recent call last):
    File «», line 1, in
    atm.next()
    AttributeError: ‘generator’ object has no attribute ‘next’
    >>> atm.__next__()
    ‘$100’
    >>> bank.__next__()
    Traceback (most recent call last):
    File «», line 1, in
    bank.__next__()
    AttributeError: ‘Bank’ object has no attribute ‘__next__’

    1. lizz

      Спасибо за коммент. Вместо bank должно быть, конечно, atm. Поправил пост.

      1. lizz

        «Съеденые» html’ом exception’ы тоже восстановил.

  2. PythonNoob

    Огромное спасибо! Исправьте опечатку во фразе «но они получить вам надо будет» — лишнее слово «они».

    1. lizz

      Спасибо. Перефразировал предложение чтобы оно было более точным.

  3. Стас

    Здорово! просто и понятно, читаю лутца и бизли, но не как немог собрать в кучу все понятия! только при прочтении понял как работает yield и для чего она. спасибо большое!

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: