I tried to print all the prime number less than 100 with flowing code:
def _odd_iter():
n=1
while True:
n=n+2
yield n
def _not_divisible(n):
return lambda x: x % n > 0
def primes():
yield 2
it = _odd_iter()
while True:
n=next(it)
yield n
it = filter(_not_divisible(n),it)
for n in primes():
if n<100:
print(n)
else:
break
And it works fine.
But after I change the _not_divisible function into lambda, it seems not work:
def _odd_iter():
n=1
while True:
n=n+2
yield n
def primes():
yield 2
it = _odd_iter()
while True:
n=next(it)
yield n
it = filter(lambda x:x%n>0,it)
for n in primes():
if n<100:
print(n)
else:
break
The result shows that the filter has dropped nothing.
Why doesn't it works with lambda?
The problem is that the n which is used within the lambda will always refer to the local value. If n changes in the surrounding context, it will also do so within the lambda*. If you want to capture the current value, you can use this instead:
it = filter(lambda x, n=n: x % n > 0, it)
*It's probably easier to understand if you think of the context as a dictionary in which local variables are stored and looked up and which always stays the same. Explicitly written that way your primes() function would look like this:
def primes():
ctx = {}
yield 2
ctx['it'] = _odd_iter()
while True:
ctx['n'] = next(ctx['it'])
yield ctx['n']
ctx['it'] = filter(lambda x: x % ctx['n'] > 0, ctx['it'])
Now it should be clear that when values in ctx change, that changes will also be picked up within the lambda. Basically the same also happens without the ctx dict, and that is what often leads to misunderstandings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With