关于python:Lambda不适用于过滤器

Lambda not work with filter

本问题已经有最佳答案,请猛点这里访问。

我试图用流动代码打印所有小于100的素数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

而且效果很好。但在我将_not_divisible函数改为lambda后,它似乎不起作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

结果表明,过滤器没有任何下降。

为什么它不能和lambda一起工作?


问题是lambda中使用的n始终引用本地值。如果n在周围环境中发生变化,它也会在lambda*中发生变化。如果要捕获当前值,可以使用该值:

1
it = filter(lambda x, n=n: x % n > 0, it)

*如果您将上下文看作一个字典,其中存储和查找局部变量,并且始终保持不变,那么可能更容易理解上下文。以这种方式显式编写的primes()函数如下:

1
2
3
4
5
6
7
8
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'])

现在应该清楚的是,当ctx中的值发生变化时,这些变化也将在lambda中被接受。基本上,没有ctx口述也会发生同样的情况,这常常导致误解。