Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python defining an iterator class, failed with "iter() returned non-iterator of type 'Fib'"

Tags:

I'm using python 2.7 and ipython2.7. In ipython I tried:

class Fib(object):
    def __init__(self, max):
        super(Fib, self).__init__()
        self.max = max

    def __iter__(self):
        self.a = 0
        self.b = 1
        return self

    def __next__(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

def main():
    fib = Fib(100)
    for i in fib:
        print i

if __name__ == '__main__':
    main()

Well it reports an error:

TypeError Traceback (most recent call last) in () 22 23 if name == 'main': ---> 24 main() 25

<ipython-input-21-f10bd2d06666> in main()
    18 def main():
    19     fib = Fib(100)
---> 20     for i in fib:
    21         print i
    22

TypeError: iter() returned non-iterator of type 'Fib'

This piece of code is actually from internet. The gramma seems OK to me, but how the problem happens?

Thanks.

like image 840
Troskyvs Avatar asked Dec 02 '16 01:12

Troskyvs


2 Answers

def __next__(self) is for Python 3

For Python 2 you need to add method next()

This code will work under both Python 3 and Python 2:

class Fib(object):
    def __init__(self, max):
        super(Fib, self).__init__()
        self.max = max

    def __iter__(self):
        self.a = 0
        self.b = 1
        return self

    def __next__(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

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


def main():
    fib = Fib(100)
    for i in fib:
        print(i)

if __name__ == '__main__':
    main()
like image 170
KromviellBlack Avatar answered Sep 19 '22 08:09

KromviellBlack


That's python 3 code where the iterator protocol uses the __next__ method. The best fix is to start using python 3. But if you need python 2, just change __next__ to next. The reason for the change was to make sure magic methods such as next conform to the __ naming convention.

like image 30
tdelaney Avatar answered Sep 18 '22 08:09

tdelaney