2016-08-22 47 views
4

我在很多文章/資料中看到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

回答

4

xrange是一個可迭代的,所以你可以調用iter來得到一個迭代器。

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

對不起,剛剛看到@Ryan在評論中打敗了我。 – smarx

1

此外,你應該明白一個迭代器和一個生成器是不是一回事。 可迭代的是實現__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 
>>> 
1

首先,你應該注意的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() 
相關問題