<type'generator'=“”>和<type'xrange'=“”>

时间:2016-08-22 01:05:08

标签: python iterator generator

我在很多帖子/材料中看到过xrange(num)是一个生成器/迭代器。我有几个问题。

  1. 我想知道类型&#39; xrange&#39;之间的确切区别。并输入&#39; generator&#39;
  2. 如果xrange是迭代器/生成器,则应该使用.next()方法。我不明白为什么.next()方法对下面的情况不起作用。

    def generator():
        for i in xrange(20): yield i
    

    在上面的例子中,

        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 
    

    上述功能也适用于以下类型的对象生成器:

        >>> numbers = (x for x in range(100))
    

    如果我使用xrange操作,循环开始从头开始迭代,并且没有next()操作。我知道我们可以采取明智的方式:

        for i in xrange(20):
            if (#something):
                var = i
                break
         #perform some operations
         for i in range(var,20):
             #Do something
    
  3. 但我想在var之后循环继续而不使用var。

    简而言之,xrange是否存在next()类型的操作。如果是:&#39;如何?&#39; ,否则:&#39;为什么?&#39;

3 个答案:

答案 0 :(得分:5)

xrange是一个可迭代的,所以你可以调用iter来获取迭代器。

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

答案 1 :(得分:3)

首先你应该注意一个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

最后,正如我在其他答案中没有看到的那样,xrange不是一个生成器而是它自己的对象类型的原因是因为它支持特殊的方法来使它模仿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()

答案 2 :(得分:2)

另外,你应该明白迭代器和生成器不是一回事。 iterable 是实现返回迭代器__iter__方法的任何Python对象。迭代器还必须实现__iter__方法,还必须实现next方法(Python 3中的__next__)。所以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

  

生成器是一个用于创建迭代器的简单而强大的工具。他们   像常规函数一样编写,但使用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
>>>