Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a simple prime sieve in Python

Tags:

python

I wrote a simple prime sieve (an unbounded sieve of Eratosthenes) using Python, but for some reason, it isn't working correctly. Here is the sieve:

from itertools import count

def sieve():
    nums = count(2)
    while True:
        n = next(nums)
        nums = filter(lambda k: k%n != 0, nums)
        yield n

Unfortunately, this isn't working. Instead, it just returns the same values as the count(2) iterator would.

For comparison, this:

nums = count(2)
print(next(nums))
nums = filter(lambda k: k%2 != 0, nums)
print(next(nums))
nums = filter(lambda k: k%2 != 0, nums)
print(next(nums))

will print:

2
3
5

while the sieve function will print:

2 3 4

I thought the issue was with the weird behavior of Python's lambda, but replacing this line:

nums = filter(lambda k: k%n != 0, nums)

with:

def f(k): return k%n != 0
nums = filter(f, nums)

doesn't solve the issue.

like image 380
IncongruentModulo1 Avatar asked Mar 11 '15 18:03

IncongruentModulo1


People also ask

How do you create a set of prime numbers in Python?

Step 1: Loop through all the elements in the given range. Step 2: Check for each number if it has any factor between 1 and itself. Step 3: If yes, then the number is not prime, and it will move to the next number. Step 4: If no, it is the prime number, and the program will print it and check for the next number.

How do you get primes in Python?

Python Program for prime numberInitialize a for loop starting from 2 ending at the integer value of the floor of the square root of the number. Check if the number is divisible by 2. Repeat till the square root of the number is checked for. In case, the number is divisible by any of the numbers, the number is not ...

How do you print prime numbers from 1 to 100 in Python?

num1 = input("Input a number: ") num2 = input("Input another number: ") for x in range(num1,num2): prime = True for i in range(2,x): if (x%i==0): prime = False if prime == True: print x print "Done......" It classifies 1 as a Prime Number, which is incorrect.


1 Answers

The problem is that the lambda is always referring to the latest value of n, not the one used when lambda was created. The simplest way around it is to capture the value explicitly using a keyword argument:

from itertools import count

def sieve():
    nums = count(2)
    while True:
        n = next(nums)
        nums = filter(lambda k, n=n: k%n != 0, nums)
        yield n

This Python gotcha is well-documented in various StackOverflow answers. To be fair, the same behavior is also shared by some other languages with lexical closures, such as JavaScript and Common Lisp.

It might be what you meant by "weird behavior of Python lambda" in the question, although this behavior has nothing to do with lambda, but with what a closure really captures when referring to a mutable variable — in Python, JavaScript and Common Lisp it captures the latest value of the variable, while in Scheme it captures the value of the variable as it was at the time the closure was created.

like image 77
user4815162342 Avatar answered Sep 27 '22 22:09

user4815162342