我有一个算法可以生成素数列表作为生成器:
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
函数不起作用。
我该怎么办?
答案 0 :(得分:7)
这是一个更简单的程序,它说明了同样的问题。
adders = []
for i in range(4):
adders.append(lambda a: i + a)
print(adders[0](3))
虽然可以预期输出为3
,但实际输出为6
。
这是因为python中的闭包会记住变量的名称和范围,而不是创建lambda时的值。由于i
在使用lambda时已被修改,因此lambda使用最新值i
。
你的功能也会发生同样的事情。每当修改n
时,各种过滤器中的所有lambda函数也会被修改。因此,当迭代器达到9
时,所有过滤器都是7
的过滤因子,而不是5
或3
。
因为,在您的第一种方法中,每次调用_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 :(得分:4)
有效的lambda是lambda x, n=n: x%n != 0
。如果您希望在定义lambda时捕获n
,则显然需要执行此操作。否则,lambda只在查找变量名时才会查找lambda。在你的情况下,我认为这意味着在稍后的while循环迭代中锁定n
值。