Итераторы и генераторы Python3


Iterator

Итерация — одна из самых мощных возможностей Python и способ доступа к элементам коллекции.

Итератор — это объект, который может запоминать позицию обхода.

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

У итераторов есть два основных метода:iter()иnext()。

Строки, списки или объекты-кортежи можно использовать для создания итераторов:

Пример (Python 3.0+)

>>> list=[1,2,3,4]
>>> it = iter(list)    # Создать объект итератора
>>> print (next(it))   # Вывести следующий элемент итератора
1
>>> print (next(it))
2
>>>

Объекты-итераторы можно перебирать с помощью обычного оператора for:

Пример (Python 3.0+)

#!/usr/bin/python3 list=[1,2,3,4] it = iter(list) # Создать объект итератора for x in it: print (x, end=" ")

Выполнение вышеуказанной программы дает следующий вывод:

1 2 3 4

Вы также можете использовать функцию next():

Пример (Python 3.0+)

#!/usr/bin/python3 import sys # Импортировать модуль sys list=[1,2,3,4] it = iter(list) # Создать объект итератора while True: try: print (next(it)) except StopIteration: sys.exit()

Выполнение вышеуказанной программы дает следующий вывод:

1
2
3
4

Создание итератора

Чтобы использовать класс в качестве итератора, необходимо реализовать в классе два метода: __iter__() и __next__().

Если вы уже понимаете объектно-ориентированное программирование, вы знаете, что у классов есть конструктор. Конструктор Python — это __init__(), который выполняется при инициализации объекта.

Для получения дополнительной информации см.:Объектно-ориентированное программирование в Python 3

Метод __iter__() возвращает специальный объект-итератор, который реализует метод __next__() и сигнализирует о завершении итерации через исключение StopIteration.

Метод __next__() (next() в Python 2) возвращает следующий объект итератора.

Создайте итератор, который возвращает числа, начиная с начального значения 1 и увеличивая на 1 на каждом шаге:

Пример (Python 3.0+)

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() myiter = iter(myclass) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter))

Вывод после выполнения:

1
2
3
4
5

StopIteration

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

Остановить выполнение после 20 итераций:

Пример (Python 3.0+)

class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)

Вывод после выполнения:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Генератор

В Python функции, использующие `yield`yield, называются генераторами (generator).

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

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

Когда в функции-генераторе используется `yield`yield-инструкция, выполнение функции приостанавливается, иyieldвыражение после `yield` возвращается как значение текущей итерации.

Затем каждый раз, когда вызывается метод генератораnext()`__next__()` или для итерации используется циклfor`for`, функция возобновляет выполнение с того места, где она была приостановлена в последний раз, пока не встретит очереднойyield`yield`-инструкция. Таким образом, функция-генератор может выдавать значения шаг за шагом, без необходимости вычислять и возвращать все результаты сразу.

Вызов функции-генератора возвращает объект-итератор.

Ниже приведён простой пример, демонстрирующий использование функций-генераторов:

Пример

def countdown(n): while n > 0: yield n n -= 1 # Создать объект-генератор generator = countdown(5) # Получить значения путём итерации по генератору print(next(generator)) # Вывод: 5 print(next(generator)) # Вывод: 4 print(next(generator)) # Вывод: 3 # Используйте цикл for для перебора генератора for value in generator: print(value) # Вывод: 2 1

В приведённом выше примереcountdown— это функция-генератор. Она использует инструкции yield, чтобы постепенно выдавать числа countdown от n до 1. Каждый раз, когда выполняется инструкция yield, функция возвращает текущее значение countdown и при следующем вызове продолжает выполнение с того места, где была последняя пауза.

Создавая объект-генератор и используя функцию next() или цикл for для перебора генератора, мы можем постепенно получать значения, которые выдаёт функция-генератор. В этом примере мы сначала используем функцию next(), чтобы получить первые три значения countdown, затем используем цикл for, чтобы получить оставшиеся два.

Преимущество функций-генераторов в том, что они могут выдавать значения по запросу, избегая одновременного создания большого объёма данных и занятия большого объёма памяти. Кроме того, генераторы могут без проблем работать с другими инструментами итерации (например, с циклами for), обеспечивая краткий и эффективный способ итерации.

Выполнение вышеуказанной программы дает следующий вывод:

5
4
3
2
1

В следующем примере используется yield для реализации последовательности Фибоначчи:

Пример (Python 3.0+)

#!/usr/bin/python3 import sys def fibonacci(n): # Функция-генератор — Фибоначчи a, b, counter = 0, 1, 0 while True: if (counter > n): return yield a a, b = b, a + b counter += 1 f = fibonacci(10) # f — это итератор, возвращаемый и создаваемый генератором while True: try: print (next(f), end=" ") except StopIteration: sys.exit()

Выполнение вышеуказанной программы дает следующий вывод:

0 1 1 2 3 5 8 13 21 34 55
Другие расширения