2014-01-23 31 views
2

這是我的Fib SQUENCE迭代器:如何修改Python運算符?

class fibo: 

    def __init__(self, n=0): 
    self.n = n 
    self.x1 = 0 
    self.x2 = 1 

    def next(self): 
     if self.n == 0: 
      raise StopIteration 
     else: 
      self.n = self.n -1 
      tmp = self.x1 
      self.x1, self.x2 = self.x2, self.x1 + self.x2 
      return tmp 

    def __iter__(self): 
     return self 

結果是

>>> [i for i in fibo(15)] 
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] 

如何修改代碼,這樣,而不是遍歷前n個斐波那契數,連續調用遍歷接下來的n個數字,例如,?

>>> f=fibo(5) 

>>> [i for i in f] 
[0, 1, 1, 2, 3] 

>>> [i for i in f] 
[5, 8, 13, 21, 34] 
>>> [i for i in f] 
[55, 89, 144, 233, 377] 
>>> [i for i in f] 
[610, 987, 1597, 2584, 4181] 
+1

請修復你的縮進 – IanAuld

回答

2

爲了得到你想要的確切語法或者是直接違法,或在Python高度氣餒,因爲迭代器協議要求一個迭代保持高產StopIteration它已經這樣做了一次之後。從PEP 234,它引入了迭代器:

- Once a particular iterator object has raised StopIteration, will 
    it also raise StopIteration on all subsequent next() calls? 
    Some say that it would be useful to require this, others say 
    that it is useful to leave this open to individual iterators. 
    Note that this may require an additional state bit for some 
    iterator implementations (e.g. function-wrapping iterators). 

    Resolution: once StopIteration is raised, calling it.next() 
    continues to raise StopIteration. 

編輯思考更多一些,我覺得你想要的其實是「合法」的Python,因爲列表解析[i for i in fibo]隱式調用FIBO的__iter__方法,它因而更多或少要求一個新的迭代器(即使這是由同一個對象實現的)。所以,正確的方式來實現你想要將行爲:

class Fibo: 
    def __init__(self, n): 
     self.n = n 
     self.cnt = n 
     self.x1 = 0 
     self.x2 = 1 

    def next(self): 
     if self.cnt > 0: 
      self.cnt -= 1 
      tmp = self.x1 
      self.x1, self.x2 = self.x2, self.x1 + self.x2 
      return tmp 
     else: 
      raise StopIteration # keeps raising 

    def __iter__(self): 
     self.cnt = self.n # reset the counter here 
     return self 

哪像這樣工作的:

In [32]: f = Fibo(3) 
In [33]: it = iter(f) 
In [34]: it.next() 
Out[34]: 0 
In [35]: it.next() 
Out[35]: 1 
In [36]: it.next() 
Out[36]: 1 
In [37]: it.next() 
-> StopIteration 
In [38]: it.next() # repeated call keeps raising 
-> StopIteration 
In [39]: it = iter(f) # explicitly reset iterator 
In [40]: it.next() 
Out[40]: 2 
In [41]: it.next() 
Out[41]: 3 
In [42]: it.next() 
Out[42]: 5 
In [43]: it.next() 
-> StopIteration 

這表明所需的行爲:它不斷提高StopIteration當它耗盡,則需要明確呼叫iter重置它。這是CB的版本,它只是環繞略有不同,無需復位:

In [45]: f = fibo(3) 
In [46]: it = iter(f) 
In [47]: it.next() 
Out[47]: 0 
In [48]: it.next() 
Out[48]: 1 
In [49]: it.next() 
Out[49]: 1 
In [50]: it.next() 
-> StopIteration 
In [51]: it.next() # no need to reset! 
Out[51]: 2 
In [52]: it.next() 
Out[52]: 3 
In [53]: it.next() 
Out[53]: 5 
In [54]: it.next() 
-> StopIteration 
2

這個工作在2.7

class fibo: 

    def __init__(self, n=0): 
     self.n = n 
     self.x1 = 0 
     self.x2 = 1 
     self.current = 0 #We won't decrease n, but instead increase current until it 
          #Equals n 

    def next(self): 
     if self.n == self.current: 
      self.current = 0 
      raise StopIteration 
     else: 
      self.current +=1 
      tmp = self.x1 
      self.x1, self.x2 = self.x2, self.x1 + self.x2 
      return tmp 

    def __iter__(self): 
     return self 

f = fibo(5) 
print [i for i in f] 
print [i for i in f] 

輸出

[0, 1, 1, 2, 3] 
[5, 8, 13, 21, 34] 
1

要達到這樣的你想要什麼,但使用不同的語法,你可以使用What is the most 「pythonic」 way to iterate over a list in chunks?的答案。特別是,從one of the answers此代碼段:

def grouper(iterable, n, fillvalue=None): 
    args = [iter(iterable)] * n 
    return izip_longest(*args, fillvalue=fillvalue) 

這個函數將切片可迭代到相同大小的「塊」。您可以與您現有的fibo類的非終止版本使用:

class fibo: 
    def __init__(self): 
     self.x1 = 0 
     self.x2 = 1 

    def next(self): 
     tmp = self.x1 
     self.x1, self.x2 = self.x2, self.x1 + self.x2 
     return tmp 

    def __iter__(self): 
     return self 

結合起來,你現在可以做這樣的事情:

>>> f = grouper(fibo(), 5) 
>>> f.next() 
(0, 1, 1, 2, 3) 
>>> f.next() 
(5, 8, 13, 21, 34) 
>>> f.next() 
(55, 89, 144, 233, 377) 

注意,此修改fibo從未停止迭代,所以你會想要小心地把它給任何試圖急切迭代到最後的東西。

順便說一句,這裏是一個使用發電機,而不是一類的迭代器的替代實現:

def fibg(): 
    x1 = 0 
    x2 = 1 
    while True: 
     yield x1 
     x1, x2 = x2, x1 + x2 
0

我覺得你是以後的行爲的最佳匹配是接受的附加計數的迭代器項目產生:

class fibo: 
    def __init__(self, n=0): 
     self.x1 = 0 
     self.x2 = 1 
     self.n = n 
    def __iter__(self): 
     return self 
    def next(self, more=0): 
     if more: 
      self.n += more 
      return 
     while self.n: 
      self.n -= 1 
      current, self.x1, self.x2 = self.x1, self.x2, self.x2 + self.x1 
      return current 
     raise StopIteration 

雖然這種迭代器是technically broken,它避免了破迭代器的最嚴重的問題 - 有新項目出現,無需用戶干預;換句話說:一旦StopIteration被提出,它會不斷提高,直到你明確告訴它你想要更多的物品:

>>> f = fibo(4) 
>>> for n in f: 
... print n 
... 
0 
1 
1 
2 
>>> f.next(7) 
>>> for n in f: 
... print n 
... 
3 
5 
8 
13 
21 
34 
55