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 i
    

    In 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()
        11 
    

    The 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: "?"

+4
3

xrange , iter, .

>>> x = xrange(20)
>>> iterator = iter(x)
>>> for i in iterator:
...     if i == 6: break
...
>>> iterator.next()
7
+5

, , - . 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
>>> 
+1

, 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()
+1
source

Source: https://habr.com/ru/post/1651976/


All Articles