基于生成器编写python迭代器的最佳方法是什么?

Pet*_*ter 3 python iterator generator

我一直在寻找一种编写基于生成器的Python迭代器的好方法.我发现了很多关于迭代器主题的教程,很多关于生成器和yield语句的教程,但没有结合这两者的内容.我已经构建了一个有效的小例子,并想知道是否有更好的方法来做到这一点.

class myIterator :

    def __init__(self, n) :
        self.last = n
        self.myGen = self.myGenerator() 

    def __iter__(self) :
        return self.myGenerator()

    def next(self) :
        return self.myGen.next()

    def myGenerator(self) :
        prev = 0
        fib = 1
        while fib < self.last :
            res = fib
            yield res
            fib = fib + prev
            prev = res

        raise StopIteration
Run Code Online (Sandbox Code Playgroud)

我在真实世界的程序中使用了这种技术,可以在我的Github存储库中的SQLStatements.py中找到

最令人困惑的部分是定义next()函数.显而易见的解决方案在每次调用时都返回了第一个元素.存储包含生成器的实例变量有效,但似乎是一个kludge.

如果你知道一个更好的方法来做这个或一个涵盖这个主题的好教程,请告诉我.

编辑:@MartijnPieters发布的第三个例子完全解决了这个问题.保存self.next中的self.generator.next函数提供了下一个函数.我希望这有助于其他人试图解决这个问题.

Mar*_*ers 8

迭代器协议由两部分组成.该__iter__方法是最重要的方法,当您iter()在对象上使用时,它应该返回迭代器.

只需更换的身体__iter__myGenerator; 无需提出StopIteration:

class myIterator:
    def __init__(self, n):
        self.last = n

    def __iter__(self):
        prev = 0
        fib = 1
        while fib < self.last:
            res = fib
            yield res
            fib += prev
            prev = res
Run Code Online (Sandbox Code Playgroud)

现在iter(myIterator(10))是一个迭代器并且有一个.next()方法.

如果希望您的类直接用作迭代器,则需要__iter__返回self并提供.next()方法.

一个.next()方法为每个函数体生成一个元素(并使用return somevalue).生成器只是一个函数yield,实际上,这样的方法本身为你实现了迭代器协议(包括.next()).

如果您要使用.next()它,它将看起来像这样:

class myIterator:
    def __init__(self, n):
        self.last = n
        self.prev = 0
        self.fib = 1

    def __iter__(self):
        return self

    def next(self):
        if self.fib < self.last:
            res = self.fib
            self.fib += self.prev
            self.prev = res
            return res

        raise StopIteration
Run Code Online (Sandbox Code Playgroud)

或者您可以重复使用.next()您的生成器的方法:

class myIterator:
    def __init__(self, n):
        self.last = n
        self.next = self.myGenerator().next  # Use the generator `.next`

    def __iter__(self):
        return self

    def myGenerator(self):
        prev = 0
        fib = 1
        while fib < self.last:
            res = fib
            yield res
            fib += prev
            prev = res
Run Code Online (Sandbox Code Playgroud)