2017-03-02 58 views
1

我想做一個發電機。那個生成器應該是可迭代的。這基本上是這樣,我可以將生成器插入現有的框架。如何使一個發電機,這是由另一個發電機組成

這是我到目前爲止的代碼。

class Iter1(object): 

    def __init__(self, iterable=None): 
     self.iterable = iterable 

    def __iter__(self): 
     if self.iterable is None: 
      self.iterable = Iter2() 
     return self.iterable 

    def next(self): 
     for thing in self.iterable: 
      yield thing 


class Iter2(object): 

    DEFAULT_PATH = r"/Users/Documents/stuff.txt" 

    def __init__(self, path=None): 
     self.path = path or self.DEFAULT_PATH 

    def __iter__(self): 
     return self 

    def next(self): 
     with open(self.path, 'r') as f: 
      for line in f: 
       yield line 


if __name__ == "__main__": 
    iterable = Iter1() 
    for thing in iterable: 
     print(thing) 

這段代碼有兩個問題。第一個是返回(產生)的東西不是文件中的一行,而是另一個生成器對象。 第二個是它不返回文件中的行數,它只返回無數的行。我知道那是因爲我每次打電話next在我再次打開該文件,但然後我不知道如何產生每行沒有加載到內存中的整個文件。

回答

1

PEP 234 -- Iterators:)由ITER的任一形式(返回

迭代器對象都有一個下一個() 方法。此方法或者返回迭代中的下一個值,或者提高StopIteration(或派生異常類) 以表示迭代結束。任何其他異常應認爲是 表示錯誤,應正常傳播, 不意味着迭代結束。

您從next()返回一個迭代器,這就是爲什麼它不按預期工作。相反,您應該每次調用next()時返回一個值。

此外,有__iter__()返回self是有點奇怪。通常假設多次調用iter(sequence)將返回多個新的迭代器,每個迭代器都從序列的開始處開始,但代碼並非如此。

+0

你說的話很有道理,但我不太明白問題出在我的代碼中。 'iter2'中的'next'方法應該從文件中產生一行,不是嗎?這應該意味着'Iter1'的'next'方法也產生一個單行,不是? –

+1

@GreeTreePython不,在next()裏面使用'yield'是不對的。在這種情況下,你的迭代器包裝可以做這樣的事情:'def next(self):return next(self.iterator)'。 Python本身會重複調用你的'next()'方法,並且每次都會返回一個值,或者在沒有更多的時候拋出'StopException'。由於您要包裝的迭代器具有相同的「next」行爲,因此您可以直接轉發它。 – ephemient