iterable - это объект, у которого есть либо метод
__iter__, либо
__getitem__.
Из любого iterable можно сделать итератор, вызвав на нем функцию
iter(x) - она просто позовет
x.__iter__, если такой метод есть, а если нет - то создаст обертку, которая будет звать
x.__getitem__ на всё возрастающих элементах.
Дальше у итератора есть метод
__next__, который должен либо вернуть очередное значение, либо кинуть
StopIteration.
При этом, в зависимости от объекта, разные итераторы по нему могут быть как зависимы, так и нет - например, итераторы по
list независимы, а по
sys.stdin или
filter - зависимы.
>>> a = [1, 2, 3, 4]
>>> x = iter(a)
>>> y = iter(a)
>>> next(x)
1
>>> next(y)
1
>>> u = filter(None, a)
>>> x1 = iter(u)
>>> y1 = iter(u)
>>> next(x1)
1
>>> next(y1)
2
Обратите внимание, что после взятия значения из
x1 следующее значение из
y1 получилось другим.
(а если посмотреть на id - то окажется, что
u, x1, y1 это вообще один и тот же объект)
Про слияние с собой - не очень понял. Если мы сначала достаем значение из итератора, а выдаем его наружу когда-нибудь потом, то нам его, конечно, нужно где-то хранить. Для этого есть скажем стандартная функция
itertools.tee, которая из одного итератора делает несколько независимых копий - сохраняя результаты, которые получили в одной копии, но не в другой.