2016-07-22 72 views
7

我有一个算法,可以生成素清单作为发电机:蟒蛇过滤器不工作

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 

但是如果我把lambda函数为filter功能直接,如下图所示:

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

我只能得到一个奇怪的列表,而不是主要列表。看来filter功能不起作用。

我该怎么办?

+2

您是否尝试将其更改为'lambda x = x:...'? – TigerhawkT3

+1

这真是太奇怪了。 –

+0

该算法的第一个版本根本不适用于我。以下代码:'_ = primes();下一页打印(_);下一页打印(_);然后打印(_);'打印'2',然后'3',然后挂起。你使用的是什么版本的Python? –

回答

6

这是一个简单的程序,它说明了同样的问题。

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

尽管人们所期望的输出是3,实际输出为6。 这是因为Python中的闭包在创建lambda时会记住变量的名称和范围,而不是它的值。由于在使用lambda时i已被修改,所以lambda使用最新值i

同样的事情发生在你的函数中。每当修改n时,各种过滤器中的所有lambda函数也会被修改。因此,迭代器到达9时,所有滤波器都是过滤因子7,而不是53

因为在第一种方法中,每次调用_not_divisible时都会创建一个新范围,该功能按预期工作。

如果你绝对必须直接使用lambda,你可以使用第二个参数是这样的:

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

谢谢@merlyn,你给出了很好的答案 –

4

的作品是lambda x, n=n: x%n != 0拉姆达。如果你想在定义lambda时捕获n,你显然需要这样做。否则,lambda只能在计算lambda时查找变量名。在你的情况下,我认为这意味着在稍后的while循环中锁定n值。

+0

有什么区别方式闭包在Python 2和Python 3中工作? –

+1

@ juanpa.arrivillaga没有区别......但是这段代码依赖于python 3,因为在python 3中'filter'返回一个生成器而不是一个计算值。 – donkopotamus

+0

@donkopotamus OH当然!您应该将其作为答案发布。 –