无限缓存生成器

时间:2018-01-04 20:50:04

标签: python generator primes

我正在研究一个需要大量小素数的项目。我想创建一个可以永远运行的生成器,但是缓存已经生成的值。到目前为止,这是我的代码。

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

此代码的问题在于,如果多个源生成新素数,它们将跳过另一个生成的素数。我该如何解决这个问题?

2 个答案:

答案 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

这将从startend 获取当前生成器的素数,而不是从头开始。你试图多次使用prime_sieve的结果,但正如我之前提到的,旧素数将会耗尽。这就是为什么它会跳过已经生成的素数。

您可能会发现next是一个有用的函数,而不是for循环。您也可以考虑使用itertools中的函数。