迭代器的意外行为

我尝试使用迭代器来实现 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

当两个注释行未注释时,它可以工作(吐出具有所需素数的迭代器对象)。否则,它只会遍历每个数字。


我期待着您的回答:) 谢谢!


犯罪嫌疑人X
浏览 103回答 3
3回答

largeQ

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)中。棘手的部分来了。L1是filter object其值仅按需计算。因此,在第二次迭代中,当prime=next(L1)执行时,仅计算一个值L。现在 lambda 使用 prime as2并计算一个值,即3( 3%2!=0) ,即 now prime。L2=filter(lambda x: x % prime != 0 or x == prime, L1)(的值L2是惰性计算的,即仅按需计算的值。现在您yield prime将屈服3。在第三次迭代prime=next(L2)中。现在事情变得有点复杂了。要从中获得一个值,L2您需要计算一个值,L1而要计算一个值L1,您需要计算一个值L。如果你没记错的话L,现在将 yield4它将被用于L1产生一个值。但最新的参考prime是3. 4%3!=0被评估为True。所以,L1产量4。因此,计算要产生的值L2 4%3!=0is 评估为Trueso prime=next(L2)is 4。对进一步的迭代应用相同的逻辑,您会发现 5,6,7,8,9... 将在进一步的迭代中产生。

拉丁的传说

您prime在 lambda 中使用变量,这是您从封闭范围继承的引用。当您的代码评估 lambda 时,它将使用在继承引用的范围内绑定到该引用的任何值。当您不使用tee和评估列表时,所有 lambda 函数都是相同的,并且对prime.tee工作原理是将结果存储在一个列表中,并在您稍后再次询问时从该列表中将它们提供给您,因此对于它的每个值prime实际上将过滤器应用于来自的所有值Lprime您可以通过在 的范围内绑定来解决此问题,方法lambda是将其作为具有默认值的参数传递。这将该值保存为函数对象的一部分,prime然后引用是对该存储值的本地引用。

扬帆大鱼

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 python3def 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 candidatefor prime in sieve_primes():    print(prime)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python