Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Python

Итераторы в Python: как они работают и как создать свои

Итераторы в Python

Узнайте, как функционируют итераторы Python, как обходить их с циклами for или функцией next(), и как создавать пользовательские или бесконечные итераторы с помощью протокола итератора.

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

Итераторы в Python

Итераторы повсюду в Python. Они лежат в основе циклов for, генераторов списков, генераторов и многих встроенных структур данных, часто работая за кулисами.

Итератор — это просто объект, выдающий данные по одному элементу за раз. В Python любой объект, реализующий методы __iter__() и __next__(), считается итератором.

Когда объект может предоставить итератор, он называется итерируемым. Большинство встроенных контейнеров — списки, кортежи, строки, словари — являются итерируемыми. Встроенная функция iter() вызывает метод __iter__() объекта для получения итератора.


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

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

# определяем список
my_list = [4, 7, 0, 3]
# получаем итератор с помощью iter()
my_iter = iter(my_list)
# итерируем через next()
# Вывод: 4
print(next(my_iter))
# Вывод: 7
print(next(my_iter))
# next(obj) то же, что obj.__next__()
# Вывод: 0
print(my_iter.__next__())
# Вывод: 3
print(my_iter.__next__())
# Это вызовет ошибку, элементы закончились
next(my_iter)

Вывод

4
7
0
3
Traceback (most recent call last):
  File "<string>", line 24, in <module>
next(my_iter)
StopIteration

Более естественный способ итерации — цикл for, который автоматически управляет жизненным циклом итератора.

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

Как цикл for работает с итераторами

Цикл for внутренне преобразуется в:

for element in iterable:
    # сделать что-то с element

что эквивалентно следующей логике:

# создать объект итератора из итерируемого
iter_obj = iter(iterable)
# бесконечный цикл
while True:
    try:
        # получить следующий элемент
        element = next(iter_obj)
        # сделать что-то с элементом
    except StopIteration:
        # если StopIteration возбуждён, выйти из цикла
        break

Это показывает, что цикл for по сути бесконечный цикл, полагающийся на протокол итератора и исключение StopIteration для завершения.


Создание пользовательских итераторов

Создание итератора с нуля просто: реализуйте __iter__() для возврата экземпляра итератора (часто self) и __next__() для выдачи следующего значения или возбуждения StopIteration при завершении.

Ниже — пример, выдающий последовательные степени двойки до заданного пользователем максимального показателя.

class PowTwo:
    """Итератор, выдающий степени двойки."""
    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
# создать объект
numbers = PowTwo(3)
# создать итерируемый из объекта
i = iter(numbers)
# Использование next для получения следующего элемента
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))

Вывод

1
2
4
8
Traceback (most recent call last):
  File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module>
print(next(i))
File "<string>", line 18, in __next__
raise StopIteration
StopIteration

Использование цикла for с пользовательским итератором так же просто:

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

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

Итераторы могут быть неограниченными. Встроенный iter() принимает вызываемый объект и значение-сентинел: он многократно вызывает функцию, пока возвращаемое значение не станет равно сентинелу. Например:

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

Поскольку int() всегда возвращает 0, iter(int, 1) никогда не видит сентинел, производя бесконечный итератор.

Можно также создать свой бесконечный итератор, например, выдающий все нечётные числа:

class InfIter:
    """Бесконечный итератор, возвращающий последовательные нечётные числа."""
    def __iter__(self):
        self.num = 1
        return self
    def __next__(self):
        num = self.num
        self.num += 2
        return num

Пример запуска:

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

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

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

Для более простого способа создания итераторов изучите генераторы Python с yield.

Python

  1. Освоение типов данных в Python: практическое руководство
  2. Мастерство операторов Python: Полное руководство
  3. Оператор pass в Python: практическое руководство
  4. Аргументы функций в Python: позиционные, именованные и параметры по умолчанию
  5. Словари в Python: создание, манипуляции и продвинутые техники
  6. Замыкания в Python: как вложенные функции захватывают переменные
  7. Модуль datetime в Python: практическое руководство по датам, времени и часовым поясам
  8. Освоение Python time.sleep(): лучшие практики, многопоточность и реальные примеры
  9. Обзор Python: высокоуровневый, читаемый, интерактивный и объектно-ориентированный язык
  10. Числа в Python: Неизменяемые числовые типы данных