1

I am very new in Python and I am finding some difficulties trying to understand how exactly works this generator implementation example calcolating Fibonacci squence:

class Fib:
    def __init__(self, nn):
        print("__init__")
        self.__n = nn
        self.__i = 0
        self.__p1 = self.__p2 = 1

    def __iter__(self):
        print("__iter__")       
        return self

    def __next__(self):
        print("__next__")               
        self.__i += 1
        if self.__i > self.__n:
            raise StopIteration
        if self.__i in [1, 2]:
            return 1
        ret = self.__p1 + self.__p2
        self.__p1, self.__p2 = self.__p2, ret
        return ret

for i in Fib(10):
    print(i)

So I have this Fib class. As usual it contains the __init__() constructor method that take the number of wich I wand to calculate the Fibonacci seqience and set to 0 the i property (because 0 is the first Fibonacci number of each sequence) and set 1 the second and the third number of the sequence (so it starts from 0,1,1).

Then I have the __iter__() method that return itself (so is it returnin a Fib object, is it correct?).

Finnally there is the __next__() method that should return the next item of the seuqence. When the last element is reached it raise a StopIteration exception. Otherwise it calculate the next fibonacci number and return it.

Outside the generator class I am using this for loop:

for i in Fib(10):
    print(i)

to calculate the first 10 Fibonacci number.

And here I have some doubts:

1) When I do Fib(10) I am calling the constructor (the __init__() method), so I am calling it one time. Is it correct?

2) The __next__() method is called when I have to obtain the next Fibonacci number. Ok...But who is calling this method? I suppose that it is automatically called by the FOR loop but I am not visualizing how it happens.

3) The FOR loop it seems to me that it is calling the constructor (__init__() method passing to it the number of which it have to calculate the Fibonacci sequence. But what is the sens of the __iter__() method. Who is calling it?

AndreaNobili
  • 40,955
  • 107
  • 324
  • 596
  • 3
    This is not a generator. This is an iterator. Essentially, your question boils down to understanding the iterator protocol in Python – juanpa.arrivillaga Dec 31 '19 at 15:03
  • @juanpa.arrivillaga iterator and generator are not the same thing? – AndreaNobili Dec 31 '19 at 15:05
  • 1
    My advice to you is to use the debugger, if you have PyCharm, click a line number to set a break point, `shift+f9` to run the debugger and `alt+shift+f7` to step through. You will see exactly what is going on. – BpY Dec 31 '19 at 15:07
  • 2
    No they aren't. All generator objects are iterators, but not all iterators are generators. A generator is returned from either a generator function (a function that uses the yield keyword) or a generator expression (like a list comprehension but with () brackets instead of []). Iterators are objects that implement `__iter__` and `__next__`. *Iterables*, like a list or other containers, only implement `__iter__` which should return an iterator. Generators are basically convenient ways of writing iterators – juanpa.arrivillaga Dec 31 '19 at 15:09
  • 1
    Anyway, I closed as a duplicate because there are many many questions on the iterator protocol. Here is a pretty good write-up that goes into more details: https://treyhunner.com/2016/12/python-iterator-protocol-how-for-loops-work/ – juanpa.arrivillaga Dec 31 '19 at 15:15
  • @juanpa.arrivillaga: `terators are objects that implement __iter__ and __next__. ` I think iterators just need to implement __next__ and iterables need to implement __iter__. Am I correct? – abhiarora Dec 31 '19 at 15:28
  • @abhiarora no, iterators must implement both `__iter__` **and** `__next__`, and they must return `self` from `__iter__`, i.e. `iter(iterator) is iterator` will evaluate to `True`. Read the link I posted in my previous comment, it is a very good and detailed overview of Pythons iterator protocol – juanpa.arrivillaga Dec 31 '19 at 15:30
  • Well. I have just tired an example in which a class `it` has only __iter__ method which returns an instance of class `i` which has only __next__ method (along with __init__) – abhiarora Dec 31 '19 at 16:28

0 Answers0