Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python filter doesn't work

I have an algorithm that can generate a prime list as a generator:

def _odd_iter():
    n=3
    while True:
        yield n
        n=n+2

def _not_divisible(n):
    return lambda x: x % n > 0

def primes():
    yield 2
    L=_odd_iter()
    while True:
        n=next(L)
        yield n
        L=filter(_not_divisible(n), L)

x=1
for t in primes():
    print(t)
    x=x+1
    if x==10:
        break

But if I put the lambda function into the filter function directly, like below:

def primes():
    yield 2
    L=_odd_iter()
    while True:
        n=next(L)
        yield n
        L=filter(lambda x: x%n>0, L)

I can get only an odd list, not a prime list. It seems the filter function doesn't work.

What can I do?

like image 583
Wei Tang Avatar asked Jul 22 '16 04:07

Wei Tang


People also ask

What does filter () do in Python?

Python's filter() is a built-in function that allows you to process an iterable and extract those items that satisfy a given condition. This process is commonly known as a filtering operation.

How do you apply a filter in Python?

filter() in python The filter() method filters the given sequence with the help of a function that tests each element in the sequence to be true or not. syntax: filter(function, sequence) Parameters: function: function that tests if each element of a sequence true or not.

Does Python filter return a list?

In Python 2, filter() returns an actual list (which is not the efficient way to handle large data), so you don't need to wrap filter() in a list() call. Here are some other examples. Try it out: # lambda is used in place of a function print(filter(lambda x: x % 2 !=

Is a filter object iterable?

The filter object is of the iterable type. It retains those elements which the function passed by returning True. We can also convert it to List or Tuple or other types using their factory functions. In this tutorial, you'll learn how to use the filter() function with different types of sequences.


2 Answers

Here's a simpler program which illustrates the same problem.

adders = []
for i in range(4):
    adders.append(lambda a: i + a)
print(adders[0](3))

While one would expect the output to be 3, the actual output is 6. This is because a closure in python remembers the name and scope of a variable rather than it's value when the lambda was created. Since, i has been modified by the time the lambda is used, the lambda uses the latest value of i.

The same thing happens in your function. Whenever n is modified, all the lambda functions in the various filters also get modified. So, by the time the iterator reaches 9, all the filters are filtering factors of 7, not 5 or 3.

Since, in your first approach you are creating a new scope with each call to _not_divisible, the function works as intended.

If you absolutely must use a lambda directly, you can use a second argument like this:

def primes():
    yield 2
    L=_odd_iter()
    while True:
        n=next(L)
        yield n
        L=filter(lambda x, n=n: x%n>0, L)
like image 87
merlyn Avatar answered Oct 06 '22 22:10

merlyn


The lambda that works is lambda x, n=n: x%n != 0. You apparently need to do this if you want n to be captured at the time the lambda is defined. Otherwise a lambda only looks up the variable name when it gets around to evaluating the lambda. In your case I think that meant locking onto an n value in a later iteration of the while loop.

like image 28
Trevor Merrifield Avatar answered Oct 06 '22 22:10

Trevor Merrifield