Discuss / Python / 请问下_not_divisible()函数参数的问题

请问下_not_divisible()函数参数的问题

Topic source

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

定义这个函数的时候只有n,这里使用的时候怎么理解it的元素作为参数进入呢

感觉这个例子作为filter()初学者教程有点太难了,我观察了好久好久,还是没理解透彻。不过有了个小小的发现: 如果将

 it = filter(_not_divisible(n), it)

改为

 it = filter(_not_divisible, it)

也会有结果,不过结果会不对(多了很多不是素数的值)

这说明在这个表达式中,n是起了作用的。

此段代码在百度百科中有,可能是已经优化过后的实现。作为教程我觉得应该先先用一段未经优化的代码(一步一行分解讲解)作示例,然后再在最后展示经过彻底优化过后的代码以便对照提升。

太晚了,明天继续研究这一段代码。

终于想明白了,是lambda的嵌套作用域原理:

#埃氏筛选法求素数
#理解这段代码,要先理解埃氏筛选法的数学基本原理

def _odd_iter():
    n = 1
    while True:
        n += 2
        yield n


def _not_divisible(n):
    return lambda x: x % n > 0
    #如果将此函数作用于某对象,则lambda语句会获取1个参数x和1个操作数(我给它取的名字)n,这步操作非常高级,不适合作为初学者教程
    #这步操作的技巧名叫作:“嵌套lambda”,即lambda出现在def中的情况,关于此段的详细说明,请参照《python学习手册》(中文第四版)P.487,
    #书中代言,“这可以工作,但是这种代码让人相当费解.出于对可读性的要求,通常来说,最好避免使用嵌套的lambda”


def primes():
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n #身兼两职的语句:一是提取当前第一个值,二是将此n值传递给下一行,下一行的lambda参数n即来自此n,作用原理即是lambda的嵌套作用域,它可以获取到上层作用域的变量值.
        it = filter(_not_divisible(n),it) # 提取不能被n整除的序列,并传递给下轮循环(it的值已经改变)
        # 现在道生了另一个难点,即,当前这个while循环会永远进行下去吗?
        # 答案是:yes!所以需要在调用时指定其上限
        # it的初始状态其实应该是[3,5,7,9,...],n的初始值应该是3,然后提取3(yield n),然后将序列与n进行整除测试,如果不能整除,则留下,然后,生成新序列
        # 对新生成的序列提取第1个数 yield n(此时n==5),依次类推……
        # 所以用程序实现埃氏筛选法的本质,是不断的从中提取序列第一个值,重点就在“提取”,而非后面的剩下的数的筛选, 而这也正是埃氏筛选法的原理
        # 深刻理解了埃氏筛选法数学原理,这代码也就相对简单了.这段代码的令人费解的地方,正在于lambda的嵌套
        # 此外,可以去网上搜索一下,有其它的一些深入的优化的代码实现方式,原理可能略有差异,同时可以对比常见的传统素数筛选算法以及非解释型语言(特别是 C 语言)的实现方式,以便加深理解

l = 0
for n in primes():
    if n < 1000:
        print(n,end='\t')
        l += 1# 计数,每10个1行
        if l % 10 ==0:
            print()
    else:
        break

廖雪峰

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

你把

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

改为:

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

理解成:

传入n,返回一个函数f(x),它判断x是否能被n整除

碧蓝右耳

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

感谢楼上两位大牛的说明,我终于领会了。原先我也是卡在这个地方好久,理解不能。

但我还是有一个要点不太明白。 如果这个it是个有限序列,那么无疑,在filter之后,生成了一个新有限序列,而且计算就完成了。但现在it是个无限序列且惰性求值,那么在filter这行执行结束之后,新的it是求值到序列中的哪个点呢。 还是说,it是在原来生成器的基础上,外面再包了一层filter,每当next(it)的时候,新的n值就经过一层层filtet出来

举例来说,当n=11时, it其实是

filter(_not_divisible(11), filter(_not_divisible(7), filter(_not_divisible(5), filter(_not_divisible(3), _odd_iter() )))) 这样的情况

如果是这样的话,岂不是随着已求素数的增加,嵌套级数越来越深,那会不会超过python能支持的堆栈(或者别的什么)的限制,导致不能计算。


  • 1

Reply