Python. Итераторы и генераторы

05 Авг 2019 , 1459

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


numbers = [1,2,3,4,5]
for i in numbers:
    print(i)

Посмотрим , как список numbers реализует протокол итератора. С помощью метода __iter__() получаем итератор , а потом для этого итератора вызываем специальный метод __next__() который выводит каждый элемент и вызывает исключение StopIteration, когда следующего элемента нет

Python. Итераторы

Итератор в Python - это объект , класс которого имеет специальный метод __next__ и метод __iter__ , который возвращает итерируемый объект (в данном случае  return self).В методе __next__ итератор должен выдавать следующий элемент , а при его отсутствии должен выбрасывать исключение StopIteration 

Давайте напишем простой итератор, который реализует вывод n элементов


class SimpleIterator:

    def __iter__(self):
        #Инициализируем начальное состояние 
        self.x = 0
        #Возвращаем итерируемый объект, который реализует метод __next__
        # В данном случае возвращаем сам объект, потому что он реализует метод __next__
        return self

    def __next__(self):
         #Если текущее значение больше двух, то вызываем исключение
         if self.x > 2:
               raise StopIteration
         else:
               self.x +=1
               return self.x

for i in SimpleIterator():
     print(i)

#Результат
#1
#2
#3


Цикл for - in многое скрывает за кадром.


#Инициализруем наш итератор
simple_iterator = SimpleIterator()
#Получаем итератор
iterator = simple_generator.__iter__

while True:
    try:
        item = iterator.__next__
    except StopIteration:
        break
     print(item)



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

Давайте реализуем генератор


def simple_generator():
    x = 0
    while True:
        if x > 2:
            return
        else:
            x +=1
            yield x


  def simple_generator():
       for i in range(1,3):
           yield i

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

Для создания генераторов используется инструкция yield. Yield - это ключевое слово, которое используется примерно как return — отличие в том, что функция вернёт генератор. Когда в первый раз запускается функци, то она будет выполняться от начала , пока не дойдет до ключевого слова yield. В этом месте эта инструкция вернет генератор и приостановит свое выполнение. При повторном запуске будет происходить ещё одна итерация написанного вами цикла, возвращаться будет следующее значение — и так пока значения не кончатся

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

Вот как выглядит код для вычисления чисел Фибонначи при использовании генераторов



def fib(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

print(list(fib(100)))
print(res)

В этой статье мы научились создавать собственные итераторы и рассмотрели какой протокол лежит внутри них. Также мы ознакомились с понятием генераторы и выяснили , что это синтаксический сахар , который облегчает создание итераторов. Кроме того , мы выяснили что значение в генераторе вычисляются(генерируются) на лету , а предыдущие вычисления забываются и это делает использование генераторов полезным и необходимым, когда мы реализуем обход данных, которые занимают большой размер.

comments powered by Disqus

Подписка

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

Рубрики

Теги