2017-03-02 54 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