Q:

If range() is a generator in Python 3.3, why can I not call next() on a range?

Perhaps I've fallen victim to misinformation on the web, but I think it's more likely just that I've misunderstood something.  Based on what I've learned so far, range() is a generator, and generators can be used as iterators.  However, this code:
myrange = range(10)
print(next(myrange))

gives me this error:
TypeError: 'range' object is not an iterator

What am I missing here?  I was expecting this to print 0, and to advance to the next value in myrange.  I'm new to Python, so please accept my apologies for the rather basic question, but I couldn't find a good explanation anywhere else.

A:

range is a class of immutable iterable objects. Their iteration behavior can be compared to lists: you can't call next directly on them; you have to get an iterator by using iter.
So no, range is not a generator.
You may be thinking, "why didn't they make it directly iterable"? Well, ranges have some useful properties that wouldn't be possible that way:

They are immutable, so they can be used as dictionary keys.
They have the start, stop and step attributes (since Python 3.3), count and index methods and they support in, len and __getitem__ operations.
You can iterate over the same range multiple times.

>>> myrange = range(1, 21, 2)
>>> myrange.start
1
>>> myrange.step
2
>>> myrange.index(17)
8
>>> myrange.index(18)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 18 is not in range
>>> it = iter(myrange)
>>> it
<range_iterator object at 0x7f504a9be960>
>>> next(it)
1
>>> next(it)
3
>>> next(it)
5

