python中的lambda表达式的闭包的后期绑定和filter()产生的bug

      最近在看廖雪峰的官网学习python,看到函数式编程的filter章节那里,作者给出了一个demo是关于用filter求素数。

     文章连接在此处。点击打开链接

     文中的代码是这样子的

     filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

用filter求素数

计算素数的一个方法是埃氏筛法,它的算法理解起来非常简单:

首先,列出从2开始的所有自然数,构造一个序列:

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14, 15, 16, 17, 18, 19, 20, ...

取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:

3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,15, 16, 17, 18, 19, 20, ...

取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:

5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20, ...

取新序列的第一个数5,然后用5把序列的5的倍数筛掉:

7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,18, 19, 20, ...

不断筛下去,就可以得到所有的素数。

以下贴出代码

def odd_iterator():  #构造一个从3开始的奇数序列,注意这是一个生成器,并且是一个无限序列。
    n = 1

    while True:

        n = n + 2

        yield n

 

 

def not_divisible(n):#筛选函数

    return lambda x: x % n != 0

 

 

def primes():

    yield 2

    it = odd_iterator()# 初始序列


    while True:

        n = next(it)# 返回序列的第一个数


        yield n

        it = filter(not_divisible,it)# 构造新序列,<更改此处>


# 打印1000以内的素数:

for i in primes():

    if i < 1000:

        print(i)

    else:

        break

     

 

因为偷懒我把

it = filter(not_divisible, it)

 

  更改成了这样

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

 

  结果就出错了,想了好久,才记得这样是因为lambda有闭包,有关闭包的事情大家可以自行百度一下,我就不在这里说了。

这里我给大家一个更简单的例子体现闭包:


  #生成一个0~9list

l = [x for x in range(10)]

j = [x for x in range(10)]

 

def func(i):

    return lambda x: x != i#筛选出与i不相同的数

 

for i in range(10):

    j = filter(func, j)#不同处

for i in range(10):

    l = filter(lambda x: x != i, l)#不同处

 

print(list(l))

print(list(j))

 

输出是

[0, 1, 2, 3, 4, 5, 6, 7, 8]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

   

    首先,按照我们的思维,程序应该生成一个[]list,但是两个输出都不是,为什么呢?这里就关系到闭包的后期绑定了。

    根据闭包的后期绑定,在for循环里,闭包只会保存循环最后一个数,也就是9所以程序的实际生成的是筛选list里与9不相等的元素,因此才会生成如此结果。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值