请问下_not_divisible()函数参数的问题
Topic source感觉这个例子作为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
你把
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整除
感谢楼上两位大牛的说明,我终于领会了。原先我也是卡在这个地方好久,理解不能。
但我还是有一个要点不太明白。 如果这个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
试试能不能注册
def primes(): yield 2 it = _odd_iter() # 初始序列 while True: n = next(it) # 返回序列的第一个数 yield n it = filter(_not_divisible(n), it)
定义这个函数的时候只有n,这里使用的时候怎么理解it的元素作为参数进入呢