На этом шаге мы дадим краткую характеристику выражениям-генераторам.
По мере того, как мы все больше узнаем о протоколе итератора Python и различных способах его реализации в собственном коде, то все больше понимаем, что синтаксический сахар является повторяющейся темой.
Дело в том, что итераторы на основе класса и функции-генераторы выражают один и тот же лежащий в основе шаблон проектирования.
Функции-генераторы предоставляют краткую форму для поддержки протокола итератора в своем собственном коде и по большей части избегают многословности итераторов на основе класса. Благодаря незначительному объему специализированного синтаксиса или "горсти" синтаксического сахара, они экономят время и облегчают вашу жизнь как разработчика.
В Python и в других языках программирования эта тема довольно часто повторяется. Вместе с увеличением числа разработчиков, которые применяют шаблоны проектирования в своих программах, у создателей языков растет стимул предлагать абстракции и укороченные пути их реализации.
Именно так происходит эволюция языков, и, как разработчики, мы получаем от этого выгоду. Мы приступаем к работе со все более и более мощными структурными блоками, которые сокращают бесполезную рутину и позволяют достигать большего за меньшее время.
Ранее вы увидели, как генераторы предлагают синтаксический сахар для написания итераторов на основе класса. Выражения-генераторы (generator expressions), которые мы рассмотрим на этом шаге, добавят сверху еще один слой синтаксического сахара.
Выражения-генераторы представляют собой еще более эффективную краткую форму для создания итераторов. Благодаря простому и сжатому синтаксису, который похож на конструкцию включения в список, вы сможете определять итераторы в одной строке кода.
Приведем пример:
iterator = ('Привет' for i in range(3))
Во время выполнения итераций данное выражение-генератор порождает ту же самую последовательность значений, что и функция-генератор bounded_repeater(), которую мы написали в предыдущем разделе. Ниже приведем ее снова, чтобы освежить вашу память:
>>> def bounded_repeater(value, max_repeats): for i in range(max_repeats): yield value >>> iterator = bounded_repeater('Привет', 3)
Разве не удивительно, что однострочное выражение-генератор теперь делает работу, для выполнения которой ранее требовалась четырехстрочная функция-генератор или намного более длинный итератор на основе класса?
Но не будем бежать впереди паровоза. Давайте убедимся, что наш итератор, определенный при помощи выражения-генератора, действительно работает как ожидалось:
>>> iterator = ('Привет' for i in range(3)) >>> for x in iterator: print(x) Привет Привет Привет
Смотрится весьма неплохо! Из нашего однострочного выражения-генератора мы, похоже, получили те же самые результаты, которые мы получали из функции-генератора bounded_repeater().
Правда, есть одно маленькое предостережение: после того как выражение-генератор было использовано, оно не может быть перезапущено или использовано снова. Поэтому в некоторых случаях предпочтительнее использовать функции-генераторы или итераторы на основе класса.
На следующем шаге мы сравним выражения-генераторы и включения в список.