我正在研究一个需要大量小素数的项目。我想创建一个可以永远运行的生成器,但是缓存已经生成的值。到目前为止,这是我的代码。
from itertools import count
def prime_sieve(): # postponed sieve, by Will Ness
for c in (2,3,5,7): # original code David Eppstein,
yield c
sieve = {} # Alex Martelli, ActiveState Recipe 2002
ps = prime_sieve() # a separate base Primes Supply:
p = next(ps) and next(ps) # (3) a Prime to add to dict
q = p*p # (9) its sQuare
for c in count(9,2): # the Candidate
if c in sieve: # c’s a multiple of some base prime
s = sieve.pop(c) # i.e. a composite ; or
elif c < q:
yield c # a prime
continue
else: # (c==q): # or the next base prime’s square:
s=count(q+2*p,2*p) # (9+6, by 6 : 15,21,27,33,...)
p=next(ps) # (5)
q=p*p # (25)
for m in s: # the next multiple
if m not in sieve: # no duplicates
break
sieve[m] = s # original test entry: ideone.com/WFv4f
class cached_primes:
def __init__(self):
self.prime_gen = prime_sieve()
self.done = False
self.vals = []
for value in self._gen_new(0, 3):
pass
def get(self, start=0, end=float('inf')):
vals = self.vals
if start == 0:
lo = 0
else:
lo = bisect_left(vals, start)
if vals[-1] > end:
hi = bisect_right(vals, end, lo=lo)
yield from islice(vals, lo, hi)
return
yield from islice(vals, lo, len(vals))
yield from self._gen_new(start, end)
def _gen_new(self, start, end):
for prime in self.prime_gen:
print(prime)
self.vals.append(prime)
if start <= prime <= end:
yield prime
elif end < prime:
return
此代码的问题在于,如果多个源生成新素数,它们将跳过另一个生成的素数。我该如何解决这个问题?
答案 0 :(得分:0)
以下是我想出来的方法。虽然不是那么干净。
class cached_primes:
def __init__(self):
self.prime_gen = prime_sieve()
self.done = False
self.vals = [2]
next(self.prime_gen)
def get(self, start=2, end=float('inf')):
vals = self.vals
lo = bisect(vals, start)
if vals[-1] >= end:
hi = bisect(vals, end)
yield from islice(vals, lo, hi)
return
else:
while vals[-1] < end:
if len(vals) > lo:
bound = len(vals)
yield from takewhile(lambda p: p <=end, islice(vals, lo, bound))
lo = bound
vals.append(next(self.prime_gen))
hi = bisect(vals, end)
yield from islice(vals, lo, hi)
答案 1 :(得分:-1)
Python生成器只生成一次值。一旦价值产生,它就永远不会再产生了。
这是你的问题:
def _gen_new(self, start, end):
for prime in self.prime_gen:
print(prime)
self.vals.append(prime)
if start <= prime <= end:
yield prime
elif end < prime:
return
这将从start
到end
获取当前生成器的素数,而不是从头开始。你试图多次使用prime_sieve
的结果,但正如我之前提到的,旧素数将会耗尽。这就是为什么它会跳过已经生成的素数。
您可能会发现next
是一个有用的函数,而不是for循环。您也可以考虑使用itertools
中的函数。