问题描述:

我在很多文章/资料中看到xrange(num)是一个生成器/迭代器。我有几个关于这方面的问题。<type'generator'>和<type'xrange'之间的差异

  1. 我想知道的类型“x范围”并键入“发电机”
  2. 之间的确切区别,如果x范围是一个迭代器/发电机,它应该具有的.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 
    

但我想循环VAR后继续不使用VAR。

简而言之,xrange是否有next()类型的操作。如果是的话:'怎么样?' ,否则:'为什么?'

+2

不,因为它是可迭代的,而不是迭代器。你可以迭代多次。你可以使用'numbers = iter(xrange(20))'来获得该行为。 – Ryan

+3

“我在很多帖子/资料中看到xrange(num)是一个生成器/迭代器。” - 这些帖子是错误的。人们只是不断说出来,因为他们不知道他们在说什么,并且因为他们喋喋不休地从他人那里听到了错误的事情。 – user2357112

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

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

对不起,刚刚看到@Ryan在评论中打败了我。 – smarx

此外,你应该明白一个迭代器和一个生成器是不是一回事。 可迭代的是实现__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(), 发生器就会从其停止的位置恢复(它记住所有数据值 值和上次执行的语句)...任何可以用发生器完成的 也可以用class为基础的迭代器,如前一节所述的 。什么让发电机如此紧凑, __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 
>>> 

首先,你应该注意的x范围对象不是发电机:

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