Share This
Связаться со мной
Крути в низ
Categories
//Итераторы и генераторы в Python

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

31.01.2022Category : Python

Сегодня мы узнаем всё про итераторы и генераторы в Python. Поговорим о том, чем итераторы отличаются от итерируемых объектов и генераторов. Также разберем, как их создать с помощью __iter__, __next__ и itertools.

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

Это означает, что, если вы когда-либо использовали циклы для итерации или прогона значений в контейнере, вы использовали итератор.

В данном руководстве вы узнаете больше об итераторах в Python. Если говорить более конкретно, то:

  • Сначала мы подробно рассмотрим итераторы, чтобы понять, для чего они нужны и когда их следует использовать
  • Затем мы рассмотрим итерируемые объекты и узнаем, чем они отличаются от итераторов
  • Далее познакомимся с контейнерами и посмотрим, как они используют концепцию итераторов
  • Затем мы посмотрим на Itertools в действии
  • И наконец, мы разберем генераторы и генераторные выражения

iteratory i generatory v python 4f11fe4 - Итераторы и генераторы в Python

Что ж, давайте приступать!

Итераторы

Итератор — это объект, реализующий протокол итератора (без паники!). Протокол итератора — это не что иное, как определенный класс в Python, который также имеет метод __next()__. Это означает, что каждый раз, когда вы запрашиваете следующее значение, итератор знает, как его вычислить. Он хранит информацию о текущем состоянии итерируемого объекта, над которым он работает.

Итератор вызывает следующее значение, когда вы вызываете для него метод next(). Объект, использующий метод __next__(), в конечном счете является итератором.

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

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

iteratory i generatory v python aa50d5c - Итераторы и генераторы в Python

Лаборатория Django-разработки

За 3 месяца отработай навыки Django-разработки до профессионального уровня на серьезном проекте под руководством наставника.

Подробнее ×

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

По словам Винсента Дриссена из nvie.com, «итерируемый объект — это любой объект (не обязательно структура данных), способный возвращать итератор». Его основная цель – вернуть все его элементы. Итерируемые объекты могут представлять как конечный, так и бесконечный источник данных. Они прямо или косвенно определяют два метода:

  • __iter__(), который должен возвращать объект итератора,
  • __next()__ с помощью вызываемого им итератора.

Примечание. Часто итерируемые классы реализуют как __iter__(), так и __next__() в одном классе. При этом __iter__() возвращает себя, что делает класс _iterable_ одновременно итерируемым объектом и собственным итератором. Однако совершенно нормально возвращать другой объект в качестве итератора.

Между итераторами и итерируемыми объектами есть большая разница. Вот пример:

a_set = {1, 2, 3} b_iterator = iter(a_set) next(b_iterator) type(a_set) type(b_iterator)

В примере a_set — это итерируемый объект (множество), а b_iterator — итератор. Оба они являются разными типами данных в Python.

Хотите познакомиться со внутренней работой итератора и узнать, как он создает следующую последовательность? Давайте создадим итератор, который возвращает серию чисел. К примеру, это можно сделать так:

class Series(object):     def __init__(self, low, high):         self.current = low         self.high = high      def __iter__(self):         return self      def __next__(self):         if self.current > self.high:             raise StopIteration         else:             self.current += 1             return self.current - 1  n_list = Series(1,10)     print(list(n_list))

__iter__ возвращает сам объект итератора, а метод __next__ возвращает следующее значение из итератора. Если больше нет элементов для возврата, возникает исключение StopIteration.

Совершенно нормально, если на данный момент вы не можете написать код для итератора самостоятельно. Однако важно, чтобы вы поняли основную концепцию, стоящую за ним. Позже мы поговорим про генераторы, которые представляют собой гораздо более простой способ реализации итераторов.

Контейнеры

Контейнеры — это объекты, содержащие значения данных. Они поддерживают тесты на членство, что означает, что вы можете проверить, существует ли значение в контейнере. Кроме того, контейнеры являются итерируемыми объектами. Списки, множества, словари, кортежи и строки — все это контейнеры. Но есть и другие итерируемые объекты, такие как открытые файлы и открытые сокеты. К примеру, вы можете выполнить тесты на членство в контейнерах следующим образом:

if 1 in [1,2,3]:     print('List')  if 4 not in {1,2,3}:     print('Tuple')  if 'apple' in 'pineapple':     print('String') #string contains all its substrings # List # Tuple # String

Модуль Itertools

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

Давайте рассмотрим некоторые интересные вещи, которые вы можете сделать с функцией count из модуля itertools. К примеру, можно делать следующее:

from itertools import count sequence = count(start=0, step=1) while(next(sequence) <= 10):     print(next(sequence)) # 1 # 3 # 5 # 7 # 9 # 11 from itertools import cycle dessert = cycle(['Icecream','Cake']) count = 0 while(count != 4):     print('Q. What do we have for dessert? A: ' + next(dessert))     count+=1 # Q. What do we have for dessert? A: Icecream # Q. What do we have for dessert? A: Cake # Q. What do we have for dessert? A: Icecream # Q. What do we have for dessert? A: Cake

Вы можете узнать больше об itertools в документации.

Генераторы

Генератор — элегантный брат итератора. Он позволяет вам создавать итераторы с гораздо более простым синтаксисом, где вам не нужно писать классы с методами __iter__() и __next__().

Помните пример с итератором, который мы рассматривали ранее? Попробуем переписать код, используя концепцию генераторов:

def series_generator(low, high):     while low <= high:        yield low        low += 1  n_list = [] for num in series_generator(1,10):     n_list.append(num)  print(n_list) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Волшебное слово у генераторов — yield. В функции series_generator нет оператора возврата return. Возвращаемое значение функции на самом деле будет генератором.

Внутри цикла while, когда выполнение достигает оператора yield, возвращается значение low и работа генератора приостанавливается. Во время второго следующего вызова генератор возобновляет работу со значения, на котором он остановился ранее, и увеличивает это значение на единицу. Он продолжает цикл while и снова приходит к оператору yield.

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

Подробнее об yield и return можно прочитать в статье «Сравнение операторов yield и return в Python (с примерами)».

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

Типы генераторов

В Python генераторы могут быть двух разных типов: функции-генераторы и генераторные выражения.

Генераторная функция — это функция, в теле которой появляется ключевое слово yield. Вы уже видели пример с функцией series_generator. Это означает, что появления ключевого слова yield достаточно, чтобы сделать функцию функцией-генератором.

Выражения-генераторы являются эквивалентом list comprehension. Они могут быть особенно полезны для ограниченного варианта использования. Точно так же, как list comprehension возвращает список, генераторное выражение возвращает генератор.

Давайте посмотрим, что это означает:

squares = (x * x for x in range(1,10)) print(type(squares)) print(list(squares)) # <class 'generator'> # [1, 4, 9, 16, 25, 36, 49, 64, 81]

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

Где вы можете вставить генераторы в свой код?

Совет. Найдите места в коде, где вы делаете, к примеру, следующее:

def some_function():     result = []     for ... in ...:         result.append(x)     return result

И измените код:

def iterate_over():     for ... in ...:         yield x

Заключение

Итераторы — мощный и полезный инструмент в Python. Однако не все хорошо знакомы с его мельчайшими подробностями. В этой статье мы разобрали, что собой представляют итераторы и генераторы в Python, чем они отличаются и как используются. Надеемся данная статья была вам полезна и теперь вы понимаете концепцию итераторов немного лучше! Успехов в написании кода!

Перевод статьи «Python Iterator Tutorial».

iteratory i generatory v python b6cbbc4 - Итераторы и генераторы в Python

Лаборатория Django-разработки

За 3 месяца отработай навыки Django-разработки до профессионального уровня на серьезном проекте под руководством наставника.

Подробнее ×

  • 0 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

    Связаться со мной
    Close