***
…Вы сможете понять и объяснить такую фразу: "…итерируемый объект, для которого запрашивается итерация, чей метод __iter__ запускается методом iter; объект итератора, возвращённый итерируемым объектом, который фактически производит значения во время итерации…"?..
Это описание относится к механизму работы циклов for/while и встроенной функции iter() в языке Python (цитата из книги: Марк Лутц. Изучаем Python. М., СПб, 2020. Т. 1. С. 443. [оригинальное название – Mark Lutz. Learning Python; перевод с английского Ю.Н. Артеменко]).
Давайте разберём эту фразу по частям:
1. "итерируемый объект" (Iterable Object)
Это любой объект Python, способный возвращать свои элементы по одному за раз. Примеры: списки (list), кортежи (tuple), строки (str), словари (dict) или файлы.
Главное требование к такому объекту – наличие специального метода __iter__.
2. "для которого запрашивается итерация"
Запрос итерации происходит, когда вы используете цикл for, передаёте объект в функцию iter() или распаковываете его с помощью оператора *. В этот момент Python понимает, что ему нужно пройти по всем элементам объекта.
3. "чей метод iter запускается…"
Когда поступает запрос на итерацию, интерпретатор Python внутренне вызывает метод __iter__() этого объекта. Именно этот метод отвечает за подготовку объекта к обходу.
4. "…методом iter"
Эта часть определения может показаться избыточной, но она подчёркивает суть протокола итерации. Метод __iter__ вызывается самим механизмом языка (внутренним методом iter()). Важно понимать разницу между итерированием самого объекта и получением итератора из него.
5. "объект итератора"
Это специальный объект в Python, созданный для обхода коллекции. Он не хранит всю коллекцию целиком (хотя может ссылаться на неё), а лишь отслеживает текущее состояние обхода: какой элемент был возвращён последним и какой будет следующим.
6. "возвращённый итерируемым объектом"
Итератор не существует сам по себе для данной коллекции. Его создаёт сам итерируемый объект при вызове функции iter(). Например, когда вы пишете for x in my_list, Python сначала вызывает iter(my_list). Метод списка __iter__ создаёт и возвращает новый объект-итератор, "привязанный" к этому списку.
7. "который фактически производит значения во время итерации"
Это главная функция итератора. Именно он отвечает за выдачу следующего элемента. Когда цикл for переходит к следующей итерации, он вызывает метод __next__() у объекта-итератора. Тот вычисляет следующий элемент и возвращает его. Этот процесс продолжается до тех пор, пока элементы не закончатся.
***
Как это работает на практике
# Ручная итерация, 1-й вариант (с использованием встроенной функции next()):
my_list = [10, 20, 30] # Создаём итерируемый объект (список чисел)
list_iterator = iter(my_list) # Создаём итератор из нашего объекта
print(next(list_iterator)) # -> 10 (ИТЕРАЦИЯ: мы получили 1-й элемент)
print(next(list_iterator)) # -> 20 (ИТЕРАЦИЯ: мы получили 2-й элемент)
print(next(list_iterator)) # -> 30 (ИТЕРАЦИЯ: мы получили последний элемент)
***
# Ручная итерация, 2-й вариант (с использованием метода __next__()):
my_list = [10, 20, 30] # Создаём итерируемый объект (список чисел)
list_iterator = iter(my_list) # Создаём итератор из нашего объекта
print(list_iterator.__next__()) # -> 10 (ИТЕРАЦИЯ: мы получили 1-й элемент)
print(list_iterator.__next__()) # -> 20 (ИТЕРАЦИЯ: мы получили 2-й элемент)
print(list_iterator.__next__()) # -> 30 (ИТЕРАЦИЯ: мы получили последний элемент)
***
# Итерация с использованием встроенной функции next() и цикла while:
my_list = [10, 20, 30] # Создаём итерируемый объект (список чисел)
list_iterator = iter(my_list) # Создаём итератор из нашего объекта
while True:
try: # Перехватываем исключение StopIteration с помощью оператора try
X = next(list_iterator)
except StopIteration:
break
print(X, end=' ') # 10 20 30
***
# Итерация с использованием метода __next__() и цикла while:
my_list = [10, 20, 30] # Создаём итерируемый объект (список чисел)
list_iterator = iter(my_list) # Создаём итератор из нашего объекта
while True:
try: # Перехватываем исключение StopIteration с помощью оператора try
X = list_iterator.__next__()
except StopIteration:
break
print(X, end=' ') # 10 20 30
***
# Автоматическая итерация (с использованием цикла for):
my_list = [10, 20, 30] # Создаём итерируемый объект (список чисел)
for item in my_list: # автоматическая итерация
print(item, end=' ') # 10 20 30
***
Ключевое различие между Iterable и Iterator
• Итерируемый объект" (Iterable Object) – это то, что можно обойти. У него есть метод __iter__, но нет метода __next__ (например, список [10, 20, 30]).
• Итератор (Iterator) – это то, что обходит. У него есть метод __next__. Он является "одноразовым": после того, как вы дошли до конца, вернуться в начало без создания нового итератора нельзя.
***
Немного этимологии (вместо послевкусия послесловия)
В переводе с великого и могучего латинского:
• iteratio – повторение.
В переводе с великого и могучего английского:
• iterate – повторять
• iterable – повторяемый
***
Примечание
Встроенный текстовый dzen-редактор не позволяет сохранять отступы в публикуемом программном коде (отсутствие этих отступов в Python приведёт к ошибке!).