Iterable и Iterator: в чём разница
less_28__iterators__itertools/theory_01_iterable_vs_iterator.py
Пошагово доказывает разницу между итерируемым объектом и итератором на примере списка: список — Iterable, но не Iterator, а результат его __iter__() — уже оба сразу. Показывает, что next() работает только на итераторе, что итератор исчерпывается (StopIteration) и что оператор in для итератора срабатывает только один раз, потому что сдвигает внутренний курсор. В конце сравнивается размер в памяти списка и итератора через sys.getsizeof — итератор не растёт вместе со списком.
- isinstance(lst, Iterable) / Iterator — список только Iterable
- lst.__iter__() — получение итератора, теперь оба isinstance True
- next(lst) — TypeError: 'list' object is not an iterator
- next(lst_iterator) x7 и восьмой — StopIteration
- 3 in lst_iterator — True затем False (курсор сдвинулся)
- size(lst) vs size(lst_iterator) — 120 против 48, и это не меняется при lst*10
Что выводит: True, False; затем True, True для итератора; TypeError на next(list); числа 1..7 по одному, затем StopIteration; True затем False для `3 in`; размеры 120 и 48, потом 616 и 48.
"""iterable vs iterator
ИТЕРИРУЕМЫЙ ОБЪЕКТ - это объект, который может состоять из множества элементов.
ИТЕРАТОР - это объект, который позволяет поочерёдно получать элементы итерируемого объекта
без необходимости загружать их все в память сразу.
(Сам итератор - тоже является итерируемым объектом).
"""
from typing import Iterator, Iterable
from sys import getsizeof as size
lst = [1, 2, 3, 4, 5, 6, 7]
Показать файл целиком (71 строк)
"""iterable vs iterator
ИТЕРИРУЕМЫЙ ОБЪЕКТ - это объект, который может состоять из множества элементов.
ИТЕРАТОР - это объект, который позволяет поочерёдно получать элементы итерируемого объекта
без необходимости загружать их все в память сразу.
(Сам итератор - тоже является итерируемым объектом).
"""
from typing import Iterator, Iterable
from sys import getsizeof as size
lst = [1, 2, 3, 4, 5, 6, 7]
print(isinstance(lst, Iterable)) # True
print(isinstance(lst, Iterator)) # False
print(""" ================= 1. К итерируемому объекту можно применить iter() или __iter__() ================= """)
lst_iterator = lst.__iter__()
print(isinstance(lst_iterator, Iterable)) # True
print(isinstance(lst_iterator, Iterator)) # True
print(""" ================= 2. Но ТОЛЬКО к итератору можно применить next() или __next__() ================= """)
try:
next(lst)
except Exception as e:
print(f"{e.__class__.__name__}: {e}") # TypeError: 'list' object is not an iterator
print(next(lst_iterator))
print(next(lst_iterator))
print(next(lst_iterator))
print(next(lst_iterator))
print(next(lst_iterator))
print(next(lst_iterator))
print(next(lst_iterator))
try:
print(next(lst_iterator))
except StopIteration as e:
print(f"{e.__class__.__name__}: {e}") # StopIteration:
"""ВЫВОД: итератор может исчерпать все свои значения"""
print(""" ================= 3. Отсюда: операция in работает для итератора ТОЛЬКО ОДИН РАЗ!!! ================= """)
lst_iterator = lst.__iter__()
print('3 in lst_iterator', 3 in lst_iterator) # True
print('3 in lst_iterator', 3 in lst_iterator) # False
print(""" ================= 4. Что требует бОльшей памяти: iterator или iterable? ================= """)
print(size(lst)) # 120
print(size(lst_iterator)) # 48
# Теперь увеличим lst в 10 раз
lst_10 = lst * 10
lst_10_iterator = iter(lst_10)
print(size(lst_10)) # 616
print(size(lst_10_iterator)) # 48
"""ВЫВОД: По сути, iterator можно считать "ленивой" версией iterable-объекта:
элементы там не хранятся в полном объёме, а "выдаются" только в момент обращения
к итератору с помощью next() или __next___()
"""