Итераторы Python (__iter__ и __next__): как их использовать и зачем?

Итераторы - это объекты, которые можно повторять. В этом руководстве вы узнаете, как работает итератор и как создать свой собственный итератор, используя методы __iter__ и __next__.

Видео: Итераторы Python

Итераторы в Python

Итераторы везде в Python. Они элегантно реализованы в forциклах, пониманиях, генераторах и т. Д., Но скрыты на виду.

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

С технической точки зрения объект-итератор Python должен реализовывать два специальных метода __iter__()и __next__(), вместе называемые протоколом итератора .

Объект называется итерабельным, если мы можем получить от него итератор. Большинство встроенных контейнеров в Python, таких как: список, кортеж, строка и т. Д., Являются повторяемыми.

iter()Функция (которая , в свою очередь , вызывает __iter__()метод) возвращает итератор из них.

Итерация через итератор

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

 # define a list my_list = (4, 7, 0, 3) # get an iterator using iter() my_iter = iter(my_list) # iterate through it using next() # Output: 4 print(next(my_iter)) # Output: 7 print(next(my_iter)) # next(obj) is same as obj.__next__() # Output: 0 print(my_iter.__next__()) # Output: 3 print(my_iter.__next__()) # This will raise error, no items left next(my_iter)

Вывод

 4 7 0 3 Traceback (последний вызов последним): файл "", строка 24, в следующем (my_iter) StopIteration

Более элегантный способ автоматической итерации - использование цикла for. Используя это, мы можем перебирать любой объект, который может возвращать итератор, например список, строку, файл и т. Д.

 >>> for element in my_list:… print(element)… 4 7 0 3

Работа цикла for для итераторов

Как мы видим в приведенном выше примере, forцикл смог автоматически перебирать список.

Фактически forцикл может повторяться по любой итерации. Давайте подробнее рассмотрим, как на forсамом деле цикл реализован в Python.

 for element in iterable: # do something with element

Фактически реализован как.

 # create an iterator object from that iterable iter_obj = iter(iterable) # infinite loop while True: try: # get the next item element = next(iter_obj) # do something with element except StopIteration: # if StopIteration is raised, break from loop break

Таким образом, внутри forцикла создается объект-итератор, iter_objвызывая iter()итерацию.

Как ни странно, этот forцикл на самом деле является бесконечным циклом while.

Внутри цикла он вызывает next()получение следующего элемента и выполняет тело forцикла с этим значением. После того, как все предметы истощены, StopIterationподнимается, который захватывается изнутри, и петля заканчивается. Обратите внимание, что любые другие исключения пройдут.

Создание собственных итераторов

Создать итератор с нуля в Python просто. Мы просто должны реализовать __iter__()и на __next__()методы.

__iter__()Метод возвращает сам объект итератора. При необходимости можно выполнить некоторую инициализацию.

__next__()Метод должен возвращать следующий элемент в последовательности. Достигнув конца, и в последующих коллах он должен поднять ставку StopIteration.

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

Если вы не имеете никакого представления об объектно-ориентированном программировании, посетите Python Object-Oriented Programming.

 class PowTwo: """Class to implement an iterator of powers of two""" def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # create an object numbers = PowTwo(3) # create an iterable from the object i = iter(numbers) # Using next to get to the next iterator element print(next(i)) print(next(i)) print(next(i)) print(next(i)) print(next(i))

Вывод

 1 2 4 8 Отслеживание (последний вызов последним): файл «/home/bsoyuj/Desktop/Untitled-1.py», строка 32, в печати (следующий (i)) Файл «», строка 18, в __next__ поднять StopIteration StopIteration

Мы также можем использовать forцикл для перебора нашего класса итератора.

 >>> for i in PowTwo(5):… print(i)… 1 2 4 8 16 32

Бесконечные итераторы Python

Нет необходимости, чтобы элемент в объекте итератора был исчерпан. Итераторов может быть бесконечное количество (которое никогда не заканчивается). Мы должны быть осторожны при обращении с такими итераторами.

Вот простой пример, демонстрирующий бесконечные итераторы.

The built-in function iter() function can be called with two arguments where the first argument must be a callable object (function) and second is the sentinel. The iterator calls this function until the returned value is equal to the sentinel.

 >>> int() 0 >>> inf = iter(int,1) >>> next(inf) 0 >>> next(inf) 0

We can see that the int() function always returns 0. So passing it as iter(int,1) will return an iterator that calls int() until the returned value equals 1. This never happens and we get an infinite iterator.

We can also build our own infinite iterators. The following iterator will, theoretically, return all the odd numbers.

 class InfIter: """Infinite iterator to return all odd numbers""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num

A sample run would be as follows.

 >>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7

And so on…

Be careful to include a terminating condition, when iterating over these types of infinite iterators.

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

В Python есть более простой способ создавать итераторы. Чтобы узнать больше, посетите: Генераторы Python с использованием yield.

Интересные статьи...