Reputation: 117
I wrote some codes in python to get some primes:
N = (x for x in range(2,100))
while i<50:
n = next(N)
print(n)
N = filter(lambda x:x % n > 0,N)
i = i+1
I think it should print primes 2,3,5,7,11.... But it turns out to be 2,3,4,5,6,7... Just like the filter didn't work. I guess maybe it's a problems of lambda, which didn't provide the value of n successfully, so I just change my codes to these:
def fil(n):
return lambda x:x % n > 0
N = (x for x in range(2,100))
i = 0
while i<50:
n = next(N)
print(n)
N = filter(fil(n),N)
i = i+1
It works.
But I still doubt that, so I wrote these:
N = (x for x in range(2,100))
i = 0
while i<50:
n = next(N)
print(n)
N = filter(lambda x:x % n == 0,N)
i = i+1
Just changed the lambda x:x % n > 0 to lambda x:x % n==0. Other parts are identical. And this time it works, gives me 2^x: 2,4,8,16,32... The filter works.
It really confused me. How to explain / understand this?
Upvotes: 1
Views: 80
Reputation: 155744
filter
on Python 3 is lazy, so the filter isn't applied until the next number is requested. When you don't use closure scope for the predicate, you end up using the live value of n
, so you're effectively testing if each number is divisible by the previous number (that is, when testing 4, each filter
wrapping is rechecking whether it's divisible by 3, 5 is checked for divisibility by 4 over and over, etc.), which is never the case (I strongly suspect your output never included 1
though, since your original genexpr doesn't even produce 1).
The simplest fix to your original code is to use a default argument to bind n
at function definition time, rather than referencing it in the body of the function, which looks it up in nested scope at call time, getting a live value. All you have to do is change:
N = filter(lambda x: x % n > 0, N)
to:
N = filter(lambda x, n=n: x % n > 0, N)
Upvotes: 2