patternpythonMinor
Memoized Prime Generator
Viewed 0 times
primememoizedgenerator
Problem
Here is my code:
In first run, it will produce prime numbers as long as they are requested. On subsequent runs, it will just yield from previously generated primes. We can test this behaviour like this:
This should output:
How does it look?
def odd_numbers_from(n):
if n % 2 == 0:
n = n + 1
while True:
yield n
n = n + 2
def takeWhile(pred, lst):
for item in lst:
if pred(item):
yield item
else:
break
def takePrimes(iterator):
for n in iterator:
if not 0 in (n % k for k in takeWhile(lambda x: x**2 300:
breakIn first run, it will produce prime numbers as long as they are requested. On subsequent runs, it will just yield from previously generated primes. We can test this behaviour like this:
# -- memoized prime generator
def primes(earlier_primes=[2]):
yield from earlier_primes
for new_prime in takePrimes(odd_numbers_from(earlier_primes[-1]+1)):
print("generated new prime")
earlier_primes.append(new_prime)
yield new_prime
if __name__ == "__main__":
for k in primes():
print(k)
if k > 20:
break
print("=====")
for k in primes():
print(k)
if k > 30:
breakThis should output:
2
generated new prime
3
generated new prime
5
generated new prime
7
generated new prime
11
generated new prime
13
generated new prime
17
generated new prime
19
generated new prime
23
=====
2
3
5
7
11
13
17
19
23
generated new prime
29
generated new prime
31How does it look?
Solution
- Review
-
There are no docstrings. What do these functions do? How do I call them? What do they return?
-
The function
odd_numbers_from could be implemented using itertools.count, like this:def odd_numbers_from(n):
"""Generate the odd numbers greater than or equal to n."""
return itertools.count(n + 1 - (n % 2), 2)-
But if you started with
earlier_primes=[2,3] then you could avoid the special case here.-
The function
takeWhile is built into Python under the name itertools.takewhile.-
takePrimes is only called from primes, so would make more sense to be inlined there.-
A Python object that can be looped over using the
for statement (like the argument to takePrimes) is properly known as an iterable, not a iterator.-
Instead of
not 0 in expression, write all(expression).- Revised code
from itertools import count, islice, takewhile
def primes(earlier_primes=[2, 3]):
"""Generate the prime numbers.
>>> list(islice(primes(), 10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
"""
yield from earlier_primes
for n in count(earlier_primes[-1] + 2, 2):
if all(n % p for p in takewhile(lambda p: p**2 <= n, primes())):
earlier_primes.append(n)
yield nCode Snippets
def odd_numbers_from(n):
"""Generate the odd numbers greater than or equal to n."""
return itertools.count(n + 1 - (n % 2), 2)from itertools import count, islice, takewhile
def primes(earlier_primes=[2, 3]):
"""Generate the prime numbers.
>>> list(islice(primes(), 10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
"""
yield from earlier_primes
for n in count(earlier_primes[-1] + 2, 2):
if all(n % p for p in takewhile(lambda p: p**2 <= n, primes())):
earlier_primes.append(n)
yield nContext
StackExchange Code Review Q#88012, answer score: 4
Revisions (0)
No revisions yet.