Unexpected behavior with iterators

ixam07 :

I tried to implement the sieve of Eratosthenes with iterators (because I wanted to get more into functional programming with python). Sadly some unexpected behaviour occurred. You can see it here in this video: https://imgur.com/gallery/XfXFw4a

Here is my code:

def sieve_primes(stop=10):
    L = (x for x in range(2, stop+1))
    while True:
        prime = next(L)
        L = filter(lambda x: x % prime != 0 or x == prime, L)
        #L, M = itertools.tee(L)
        #print(list(M))
        yield prime

It works (spits out an iterator object with the desired primes) when the two commented lines are uncommented. Otherwise, it just iterates over every number.

I'm looking forward to your answers :) Thanks!

Ch3steR :
def sieve_primes(stop=10):
    L = (x for x in range(2, stop+1))
    while True:
        prime = next(L)
        L = filter(lambda x: x % prime != 0 or x == prime, L)
        yield prime

What exactly is happening in your code is given below iteration by iteration. For convenience in I represent L as L1 in 1st iteration, L as L2 in 2nd iteration, so on.

  • In 1st iteration prime=next(L) which is 2 (as expected). L1=filter(lambda x: x % prime != 0 or x == prime, L) (Values of L are calculated lazily i.e values calculated only on demand. yield prime will yield 2 expected.

  • In 2nd iteration prime=next(L1). Here comes the tricky part. L1 is filter object whose values are calculated only on demand. So, in 2nd iteration when prime=next(L1) is executed only one value is calculated from L. Now the lambda uses prime as 2 and calculates one value which is 3 (3%2!=0) which is now prime. L2=filter(lambda x: x % prime != 0 or x == prime, L1) (Values of L2 are calculated lazily i.e values calculated only on demand. Now you yield prime will yield 3.

  • In 3rd iteration prime=next(L2). Now things get little complicated. To get one value from L2 you need to calculate one value of L1 and to calculate one value L1 you need to calculate one values L. If you remember correctly L will now yield 4 which will now be used by L1 to produce one value. But the latest reference to prime is 3. 4%3!=0 is evaluated to True. So, L1 yields 4. So, calculate the value to be yielded by L2 4%3!=0 is evaluated to True so prime=next(L2) is 4.

Apply same logic for further iterations you will find 5,6,7,8,9... will be yielded in further iterations.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11787&siteId=1