Fibonacci generator iterator and infinite generators

Viewed 220

I have this FibIter generator. I'm trying to create second one using a generator expression.

def FibIter():
    yield 0
    yield 1
    x = 0
    y = 1
    while True:
        result = x + y
        x, y = y, result
        yield result

fibiter = FibIter()
fibiter_in_range = (x for i, x in enumerate(fibiter) if 100000 < i <= 100020)

Now if I run code below nothing happens.

print(list(fibiter_in_range))

and if I run code below numbers get printed, but the for loop doesn't end.

for x in fibiter_in_range:
    print(x)

I thought I can iterate through fibiter_in_range until all elements are used.

What do I not understand about generators? How to elegantly create iterator with fibonacci numbers with n in range 100000-100020?

2 Answers

The problem is that your generator never ends, and your generator expression keeps getting outputs from it, even after i reaches its upper bound.

A simple way to do what you want is to use itertools.islice:

from itertools import islice

def FibIter():
    yield 0
    yield 1
    x = 0
    y = 1
    while True:
        result = x + y
        x, y = y, result
        yield result

fibiter = FibIter()
fibiter_in_range = islice(fibiter, 10, 15)
print(list(fibiter_in_range))
# [55, 89, 144, 233, 377]

Python isn't smart enough to know that if 100000 < i <= 100020 will cause that new generator to cease yielding after 100020. As far as it knows, there may be some element later that fulfills the condition, so it needs to keep pulling to see if one eventually does satisfy it.

You could use dropwhile and takewhile to filter:

from itertools import takewhile, dropwhile

...


fibiter = FibIter()
fibiter_in_range = takewhile(lambda n: n <= 10002000,
                             dropwhile(lambda n: n < 100000, fibiter))

>>> list(fibiter_in_range)
[121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465]

This filters based on the value of the numbers though, not their index into the generator since you wrote that you want to "elegantly create iterator with fibonacci numbers with n in range 100000-100020?". I increased the upper bound for the sake of the example since it doesn't find any elements otherwise.

Related