Earlier we saw how callbacks can be better than plain functions, but we have other possible solutions. We can also create a possibly unbounded iterator that will go over the elements of our series making our code look even more straight-forward than the solution with the callback.

Solution with Callback

Just as a reminder, here is our solution with a callback. We have a function called fibonacci that goes over the elements of the series and for each element it calls the check_17 function passed to it.

examples/python/fibonacci_function_callback.py

#!/usr/bin/env python
from __future__ import print_function

def fibonacci(cb):
    values = []
    while(True):
        if len(values) < 2:
            values.append(1)
        else:
            values = [values[-1], values[-1] + values[-2]]

        r = cb(values[-1])
        if (r[0]):
            return(r[1])

def check_17(v):
    if v % 17 == 0:
        return (True, v)

    if v > 10000:
        return (True, None)

    return (False,)


if __name__ == '__main__':
    res = fibonacci(check_17)
    if (res != None):
        print(res)

The fact that we had to be able to signal to the fibonacci function when to stop made our code slightly more complex than we hoped for. We had to return a tuple in which the first element was the True/False indicator.

Create a Fibonacci iterator

Let's turn the whole thing around and let the end-user retain full control of the looping. We create a Fibonacci class that becomes iterable by the addition of the __iter__ method which just returns the object, and by having a next method (In Python 3 I think it should be __next__) that will return the next element.

The object internally will keep the current state of the iteration, which in our case means it needs to keep the last two elements of the series.

examples/python/fibonacci_iterator.py

#!/usr/bin/env python
from __future__ import print_function

class Fibonacci(object):
    def __init__(self):
        self.values = []

    def __iter__(self):
        return self

    def next(self):
        if len(self.values) < 2:
            self.values.append(1)
        else:
            self.values = [self.values[-1], self.values[-1] + self.values[-2]]
        return self.values[-1]

for f in Fibonacci():
    if f % 17 == 0:
        print(f)
        break
    if f > 10000:
        break

Calling fib = Fibonacci() will create an iterator object and as such, we'll be able to use the for in construct on it to iterate over the elements. Because the is an unbounded iteator, that is one that does not have an end, we have to make sure there is some code inside the for loop that will stop it no matter what.

This solution seem to be more simple to use than the one with callbacks