Итераторы и итерируемые объекты в Python
Итератор — это объект, с помощью которого можно перебирать коллекции. Для этого у итератора должны быть следующие методы:
Когда вы завершаете перебор коллекции с помощью итератора, он «исчерпывается». Это означает, что больше тот итератор использовать нельзя.
Итерируемые объекты
Итерируемый объект — это объект, который можно перебирать.
Объект является итерируемым, если он реализует метод __iter__ , который возвращает новый итератор.
Встроенные списки и итератор списков
Cписок — это упорядоченная коллекция элементов. Он является итерируемым объектов, поскольку у него есть метод __iter__ , который возвращает итератор. Например:
numbers = [1, 2, 3] number_iterator = numbers.__iter__() print(type(number_iterator))
В этом примере метод __iter__ возвращает итератор типа list_iterator .
Поскольку list_iterator реализует метод __iter__ , вы можете использовать встроенную функцию iter() для получения объекта итератора:
numbers = [1, 2, 3] number_iterator = iter(numbers)
Поскольку у list_iterator также есть метод __next__ , вы можете использовать встроенную функцию next() для перебора списка:
numbers = [1, 2, 3] number_iterator = iter(numbers) next(number_iterator) next(number_iterator) next(number_iterator)
Если вызвать эту функцию еще раз, вы получите ошибку StopIteration.
next(number_iterator) # ошибка StopIteration
Так происходит потому, что итератор списка был исчерпан. Чтобы повторить итерацию списка, необходимо создать новый итератор.
Это иллюстрирует разницу между списком и его итератором. Список создается один раз, а итератор создается каждый раз, когда вам нужно выполнить перебор списка.
Итераторы и итерируемые объекты
Давайте создадим класс Colors :
class Colors: def __init__(self): self.rgb = ['красный', 'зеленый', 'синий'] self.__index = 0 def __iter__(self): return self def __next__(self): if self.__index >= len(self.rgb): raise StopIteration # возвращаем следующий цвет color = self.rgb[self.__index] self.__index += 1 return color
В этом примере класс Colors играет две роли. Он одновременно является итератором и итерируемым объектом.
Класс Colors является итератором, поскольку в нем реализованы методы __iter__ и __next__ . Метод __iter__ возвращает сам объект, а __next__ возвращает следующий элемент из списка.
Класс Colors является итерабельным, поскольку реализует метод __iter__ , который возвращает сам объект, являющийся итератором.
Давайте создадим новый экземпляр класса Colors и выполним перебор его элементов с помощью цикла for:
colors = Colors() for color in colors: print(color)
После завершения перебора объект colors становится бесполезным. Если вы попытаетесь повторить итерацию, вы получите исключение StopIteration:
next(colors) # ошибка StopIteration
Если вы по новой запустите цикл for, вы ничего не получите, потому что итератор исчерпан:
for color in colors: print(color)
Чтобы повторить перебор, необходимо создать новый объект colors с атрибутом rgb . Но это неэффективно.
Различаем итераторы и итерируемые объекты
Давайте отделим итератор color от итерабельного объекта color , как это делает Python с итератором списка и списком.
class Colors: def __init__(self): self.rgb = ['красный', 'зеленый', 'синий'] def __len__(self): return len(self.rgb)
Теперь создадим класс ColorsIterator :
class ColorIterator: def __init__(self, colors): self.__colors = colors self.__index = 0 def __iter__(self): return self def __next__(self): if self.__index >= len(self.__colors): raise StopIteration # возвращаем следующий цвет color = self.__colors.rgb[self.__index] self.__index += 1 return color
Как это работает
- Метод __init__ принимает итератор, который является экземпляром класса Colors .
- Метод __iter__ возвращает сам итератор.
- Метод __next__ возвращает следующий элемент из объекта Colors .
Теперь покажем, как использовать ColorIterator для перебора объекта Colors :
colors = Colors() color_iterator = ColorIterator(colors) for color in color_iterator: print(color)
Для повторного перебора объекта Colors достаточно создать новый экземпляр ColorIterator .
Когда вы хотите перебрать объект Colors, вам нужно вручную создать новый объект ColorIterator . При этом нужно запомнить имя итератора ColorIterator .
Было бы здорово автоматизировать этот процесс. Для этого можно сделать класс Colors итерируемым объектом, реализовав метод __iter__ . Давайте это и сделаем:
class Colors: def __init__(self): self.rgb = ['красный', 'зеленый', 'синий'] def __len__(self): return len(self.rgb) def __iter__(self): return ColorIterator(self)
Метод __iter__ возвращает новый экземпляр класса ColorIterator .
Теперь вы можете выполнять перебор объекта Colors без явного создания объекта ColorIterator :
colors = Colors() for color in colors: print(color)
Внутри цикла for вызывается метод __iter__ объекта colors для получения итератора. Он используется для перебора элементов объекта colors .
Давайте поместим класс ColorIterator в класса Colors , чтобы инкапсулировать их в один класс:
class Colors: def __init__(self): self.rgb = ['красный', 'зеленый', 'синий'] def __len__(self): return len(self.rgb) def __iter__(self): return self.ColorIterator(self) class ColorIterator: def __init__(self, colors): self.__colors = colors self.__index = 0 def __iter__(self): return self def __next__(self): if self.__index >= len(self.__colors): raise StopIteration # возвращаем следующий цвет color = self.__colors.rgb[self.__index] self.__index += 1 return color
Что нужно запомнить
- Итерируемый объект — это объект с методом __iter__ , который возвращает итератор.
- Итератор — это объект с методом __iter__ , который возвращает самого себя, и методом __next__ , который возвращает следующий элемент.
- Итераторы также являются итерируемыми объектами. Однако они «исчерпываются», а итерируемые объекты — нет.
СodeСhick.io — простой и эффективный способ изучения программирования.
2023 © ООО «Алгоритмы и практика»