为了账号安全,请及时绑定邮箱和手机立即绑定

迭代器的意外行为

迭代器的意外行为

犯罪嫌疑人X 2022-07-26 21:08:39
我尝试使用迭代器来实现 Eratosthenes 的筛子(因为我想更多地使用 python 进行函数式编程)。可悲的是,发生了一些意想不到的行为。您可以在此视频中看到它:https ://imgur.com/gallery/XfXFw4a这是我的代码:def sieve_primes(stop=10):    L = (x for x in range(2, stop+1))    while True:        prime = next(L)        L = filter(lambda x: x % prime != 0 or x == prime, L)        #L, M = itertools.tee(L)        #print(list(M))        yield prime当两个注释行未注释时,它可以工作(吐出具有所需素数的迭代器对象)。否则,它只会遍历每个数字。我期待着您的回答:) 谢谢!
查看完整描述

3 回答

?
largeQ

TA贡献2039条经验 获得超7个赞

def sieve_primes(stop=10):

    L = (x for x in range(2, stop+1))

    while True:

        prime = next(L)

        L = filter(lambda x: x % prime != 0 or x == prime, L)

        yield prime

您的代码中到底发生了什么在下面逐次迭代中给出。为方便起见,我在第一次迭代中将 L 表示为 L1,在第二次迭代中将 L 表示为 L2,依此类推。

  • 在第一次迭代prime=next(L)中为 2(如预期的那样)。 L1=filter(lambda x: x % prime != 0 or x == prime, L)(的值L是惰性计算的,即仅根据需要计算的值。yield prime将产生2预期的结果。

  • 在第二次迭代prime=next(L1)中。棘手的部分来了。L1filter object其值仅按需计算。因此,在第二次迭代中,当prime=next(L1)执行时,仅计算一个值L。现在 lambda 使用 prime as2并计算一个值,即33%2!=0) ,即 now primeL2=filter(lambda x: x % prime != 0 or x == prime, L1)(的值L2是惰性计算的,即仅按需计算的值。现在您yield prime将屈服3

  • 在第三次迭代prime=next(L2)中。现在事情变得有点复杂了。要从中获得一个值,L2您需要计算一个值,L1而要计算一个值L1,您需要计算一个值L。如果你没记错的话L,现在将 yield4它将被用于L1产生一个值。但最新的参考prime34%3!=0被评估为True。所以,L1产量4。因此,计算要产生的值L2 4%3!=0is 评估为Trueso prime=next(L2)is 4

对进一步的迭代应用相同的逻辑,您会发现 5,6,7,8,9... 将在进一步的迭代中产生。


查看完整回答
反对 回复 2022-07-26
?
拉丁的传说

TA贡献1789条经验 获得超8个赞

prime在 lambda 中使用变量,这是您从封闭范围继承的引用。当您的代码评估 lambda 时,它将使用在继承引用的范围内绑定到该引用的任何值。当您不使用tee和评估列表时,所有 lambda 函数都是相同的,并且对prime.

tee工作原理是将结果存储在一个列表中,并在您稍后再次询问时从该列表中将它们提供给您,因此对于它的每个值prime实际上将过滤器应用于来自的所有值L

prime您可以通过在 的范围内绑定来解决此问题,方法lambda是将其作为具有默认值的参数传递。这将该值保存为函数对象的一部分,prime然后引用是对该存储值的本地引用。


查看完整回答
反对 回复 2022-07-26
?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

def sieve_primes(stop=10):

    L = (x for x in range(2, stop+1))

    while True:

        prime = next(L)

        L = filter(lambda x: x % prime != 0 or x == prime, L)

        yield prime下面的呢?使用生成器表达式通常比使用 map/filter/reduce 更好。


#!/usr/bin/env python3



def sieve_primes(stop=100):

    primes = []

    for candidate in range(2, stop+1):

        if not any(candidate % prime == 0 for prime in primes):

            primes.append(candidate)

            yield candidate



for prime in sieve_primes():

    print(prime)


查看完整回答
反对 回复 2022-07-26
  • 3 回答
  • 0 关注
  • 99 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信