If range() is a generator in Python 3.3, why can I not call next() on a range?
range
is a class of immutable iterable objects. Their iteration behavior can be compared to list
s: 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, range
s 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
andstep
attributes (since Python 3.3),count
andindex
methods and they supportin
,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
Related videos on Youtube
Jeff
Updated on April 28, 2020Comments
-
Jeff about 4 years
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.-
Admin over 11 yearsSee stackoverflow.com/q/13054057/395760 for the distinction between iterators and things which you can iterate over in a
for
loop. -
Jeff over 11 yearsWould it be correct to say that generators are iterables, but not iterators?
-
Oleh Prypin over 11 years@Jeff Iterables are objects that
iter
can be used on to obtain an iterator. Iterators are objects that can be iterated through usingnext
. Generators is a category of iterators (generator functions and generator expressions). At least that's what I think...
-
-
kindall over 11 yearsAnother nice feature of
range
objects is that they have a__contains__
method which can be used to test whether a value is in a range:5 in range(10) => True
-
Jeff over 11 yearsThanks for the answer; this makes sense now. The only thing I want to clear up before accepting your answer is the note in italics about a third of the way down this page, that states that "in Python 3 range() is a generator". Is this simply incorrect?
-
Oleh Prypin over 11 years@Jeff Strictly speaking, yes, it is wrong. The author of the note probably meant that in Python 3
range
is lazy (compared to Python 2 where it's just a function that returns a list). -
Lennart Regebro over 11 yearsAlso:
range(0,10,3)[3]
and9 in range(0,10,3)
. Range is pretty much a lazy list. -
temporary_user_name about 10 yearsOne of the final puzzle pieces falls into place...great answer.
-
user2399453 over 6 yearsWhat is the link between being immutable and not being directly iterable? Even an iterable object seems immutable to me so what exactly is the benefit of or reason behind a range object not being directly iterable?
-
Oleh Prypin over 6 years@user3079275 "directly iterable" is a misnomer, actually meaning "iterator". Iterators have internal state and so are mutable by definition. "Iterable" is an object, whether it is mutable or not, that can produce an iterator. Even mutable objects aren't usually iterators themselves, instead they produce iterators in a reusable manner (for example, you can iterate over the same list in two different places independently, using two iterators).