As usual, a demonstration at the Python REPL will help all of these concepts crystallize into something you can work with. We start with a list of the names of the seasons as our iterable object:
>>> iterable = ['Spring', 'Summer', 'Autumn', 'Winter']
We then ask our iterable object to give us an iterator using the iter() built-in:
>>> iterator = iter(iterable)
Next we request a value from the iterator object using the next() built-in:
>>> next(iterator)
'Spring'
Each call to next() moves the iterator through the sequence:
>>> next(iterator)
'Summer'
>>> next(iterator)
'Autumn'
>>> next(iterator)
'Winter'
But what happens when we reach the end?
>>> next(iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
In a spectacular display of liberalism, Python raises a StopIteration exception. Those of you coming from other programming languages with a more straight-laced approach to exceptions may find this mildly outrageous, but, really, what could be more exceptional than reaching the end of a collection? It only has one end after all!
This attempt at rationalizing the Python language design decision makes even more sense when one considers that the iterable series may be a potentially infinite stream of data. Reaching the end in that case really would be something to write home about, or indeed raise an exception for.