The difference between <type 'generator'> and <type 'xrange'>
I have seen many posts / materials saying that xrange (num) is a generator / iterator. I have a few questions regarding this.
- I want to know the exact difference between type 'xrange' and type 'generator'
If xrange is an iterator / generator, it must have a .next () method. I do not understand why the .next () method does not work in the following case.
def generator(): for i in xrange(20): yield iIn the example above
numbers = generator() for i in numbers: if i == 6: break for i in numbers: if i == 10: break print i >>> 7 8 9 >>> print numbers.next() 11The above functions are also valid for an object generator of the type:
>>> numbers = (x for x in range(100))If I perform an xrange operation, the loop starts iterating from the beginning and there will be no next () operation. I know that we can do a smart way:
for i in xrange(20): if (#something): var = i break #perform some operations for i in range(var,20): #Do something
But I want the loop to continue after var without using var.
, () xrange. : "?", else: "?"
, , - . Python, __iter__, . __iter__, next (__next__ Python 3). , xrange , . :
class NumberCounter(object):
def __init__(self, size):
self.size = size
self.start = 0
def __iter__(self):
return self
def next(self):
if self.start < self.size:
self.start += 1
return self.start
raise StopIteration
:
>>> nc6 = NumberCounter(6)
>>> it = iter(nc6)
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
4
>>> next(it)
5
>>> next(it)
6
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in next
StopIteration
>>> for i in NumberCounter(6):
... print(i)
...
1
2
3
4
5
6
>>>
- Python, .
docs:
- . O , yield . , next() , ( )... , , , . __iter __() next() ... , , StopIteration. , , .
:
def number_counter(x):
curr = 1
while curr <= x:
yield curr
curr += 1
:
>>> for i in number_counter(6):
... print(i)
...
1
2
3
4
5
6
>>>
:
def wacky_gen():
yield 88
yield 2
yield 15
-...
>>> for i in wacky_gen():
... print(i)
...
88
2
15
>>>
, xrange :
>>> xrange_obj = xrange(10000)
>>> type(xrange_obj)
xrange
>>> gen_obj = (x for x in range(10000))
>>> type(gen_obj)
generator
>>> import types
>>> isinstance(xrange_obj, types.GeneratorType)
False
>>> isinstance(gen_obj, types.GeneratorType)
True
( )
>>> iter(xrange_obj)
<rangeiterator at 0x3e07f930>
>>> iter(xrange_obj).next()
0
Finally, since I do not see any other affected answers in this, the reason xrange is not a generator, but its own type of object is due to the fact that it supports special methods to imitate range.
>>> xrange_obj[1]
1
>>> len(xrange_obj)
10000
>>> gen_obj[1]
TypeError: 'generator' object has no attribute '__getitem__'
>>> len(gen_obj)
TypeError: object of type 'generator' has no len()