Discuss / Python / 一个很神奇的问题

一个很神奇的问题

Topic source

生成素数那里

def primes():
    yield 2
    it = _odd_iter() # 初始序列
    while True:
        n = next(it) # 返回序列的第一个数
        yield n
        it = filter(_not_divisible(n), it) # 构造新序列

这里的最后一句的 _not_divisible(n) 调用的是

def _not_divisible(n):
    return lambda x: x % n > 0

这个函数,但是调用这个不就是等于

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

这样写吗,但是这样写运行结果是错的,有大佬知道为什么吗

虽然还没有完完全全整明白,但大体上知道个大概原因了,问题出在这个n这里,

filter(_not_divisible(n), it)

这样写的时候,因为有函数调用,所以n的值正确的传给了lambda函数,不管是lambda x: x % 3 > 0 还是 lambda x: x % 5 > 0 等都是没问题的,但是

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

这样写的时候因为没有函数调用,Iterator又是惰性的,所以这里的n在我们定义这个iterator的时候并不会传进去,而是下次调用它的next()函数的时候才会。

首先梳理一下流程,通过debug发现,这个写法是每次调用next()的时候,将当前的数x 和 3~x 之间的数取余来判断,比如现在 _odd_iter() 函数 yield 回来的是9,那么会依次将它和3、5、7取余,如果余数为0则继续调用 _odd_iter()函数 yield下一个数重复前面的操作,反之则说明这个数是素数。

正是因为第二种写法没有调用函数,所以在和前面的数取余的时候它们的n全是相同的,就起不到filter的作用,比如比如现在 _odd_iter() 函数 yield 回来的是9,那么本应是依次将它和3、5、7取余,现在却变成了依次将它和7、7、7取余

大概明白你的意思,但还是不明白为什么直接写lambda就不能调用函数了。写not_divisible(n)时也有个参数n吧,难道因为直接写lambda时n不是input吗。

哦我现在明白了,因为这里的n其实是同一个n,你写lambda x:x%n>0的话,这里n是变量,一直都是最新的那个n,也就是说filter里出现的函数全是同一个函数。non_d(n)相当于输入了一个n=n0,return了一个函数,这个函数每次都是不同的函数,也就相当于保存了每次循环n的数值。

嗨养车

#5 Created at ... [Delete] [Delete and Lock User]

看下一章“返回函数”里,闭包应该就是说的这个问题。

是的,是后面的闭包。函数调用了就把n固定传进去了,而lambda写出来的时候并没有调用,所以在后面调用的时候会以那个时候的n为准


  • 1

Reply