Everyone seems to claim that xrange returns a generator but it really is its own thing:
>>> xrange(10)
xrange(10)
>>> xrange(10).__bases__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'xrange' object has no attribute '__bases__'
What I don't understand is how xrange lets you check membership.
>>> a = xrange(10)
>>> 4 in a
True
>>> 4 in a
True
If this was a real generator, the second check would fail since we have already iterated through the 4.
>>> def mygen():
... num = 0
... while num < 100:
... yield num
... num += 1
...
>>>
>>> mygen()
<generator object mygen at 0x100618b40>
>>> list(mygen())
[0, ..., 99]
>>> x = mygen()
>>> 4 in x
True
>>> 4 in x
False
There seems to be something special about xrange that lets it do membership properly, as if it overrides __contains__.
It turns out,
xrangeis indeed not a true<type 'generator'>.At the cython level there is a generator that powers the range logic, but there is also a
range_contains_longfunction which does the comparison, bypassing iteration of the generator.Therefore, to call
xrangeageneratoris slightly misleading.