I've encountered this code from Most pythonic way of counting matching elements in something iterable
r = xrange(1, 10) print sum(1 for v in r if v % 2 == 0) # 4 print sum(1 for v in r if v % 3 == 0) # 3
r is iterated once. and then it's iterated again. I thought if an iterator is once consumed then it's over and it should not be iterated again.
Generator expressions can be iterated only once:
r = (7 * i for i in xrange(1, 10)) print sum(1 for v in r if v % 2 == 0) # 4 print sum(1 for v in r if v % 3 == 0) # 0
enumerate(L) too:
r = enumerate(mylist)
and file object too:
f = open(myfilename, 'r')
Why does xrange behave differently?
Because xrange
does not return a generator. It returns an xrange object.
>>> type(xrange(10)) <type 'xrange'>
In addition to repeated iteration, xrange
objects support other things that generators don't -- like indexing:
>>> xrange(10)[5] 5
They also have a length:
>>> len(xrange(10)) 10
And they can be reversed:
>>> list(reversed(xrange(10))) [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In short, xrange
objects implement the full sequence interface:
>>> import collections >>> isinstance(xrange(10), collections.Sequence) True
They just do it without using up a lot of memory.
Note also that in Python 3, the range
object returned by range
has all the same properties.
Because the xrange
object produced by calling xrange()
specifies an __iter__
that provides a unique version of itself (actually, a separate rangeiterator
object) each time it's iterated.
>>> x = xrange(3) >>> type(x) <type 'xrange'> >>> i = x.__iter__() >>> type(i) <type 'rangeiterator'>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With