我想出了"Sieve of Eratosthenes"的 trial division 变体的Python代码:
import itertools
def sieve():
# begin with all natural numbers above 1
picker = itertools.count(2)
while True:
# take the next available number
v = next(picker)
yield v
# filter from the generator its multiples
picker = filter(lambda x: x % v != 0, picker)
它不符合我的预期。
在调试时,我得到一些行为,我不知道何时调用filter
:lambda的x
参数得到一个具体的参数,该参数是picker
中的下一个元素发电机。即使看了filter
的文档,我也不了解这种行为。
运行
s = sieve()
for i in range(5):
print(next(s))
我得到:
2
3
4
5
6
代替
2
3
5
7
11
更新:
我的错误来自对lambda如何在Python中工作的误解,更多关于here。
向lambda添加一个额外的参数可解决此问题:
picker = filter(lambda x, prime = v: x % prime != 0, picker)
答案 0 :(得分:3)
我认为问题是因为您依赖局部变量,并且您创建的生成器(使用filter()
)引用了局部变量,当生成器继续进行迭代时,这些局部变量将被覆盖。
如果您改用局部函数,则可以正常工作:
def sieve():
def selector(iterator, d):
for x in iterator:
if x % d != 0:
yield x
picker = itertools.count(2)
while True:
# take the next available number
prime = next(picker)
yield prime
# filter from the generator its multiples
picker = selector(picker, prime)
尝试list(itertools.islice(sieve(), 10))
显示:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
但是我确实需要指出,这是一个纯粹的教育性解决方案,用于说明事物的工作方式。我不会建议将此解决方案用于任何有效的代码。它在内部建立了大量的生成器,只有当您释放父生成器的句柄时才释放它们。这可能会浪费资源,并且您可以创建无限数量的质数而无需创建无限数量的生成器。