Reputation: 1038
I'm trying to make the below generator to be able to set an upper limit on the numbers returned.
Calling list(it.takewhile(lambda x: x < 100, get_primes()))
returns a list of all primes under 100 as expected but list(get_primes(100))
(which should return the same list in the same way) just returns with an empty list.
Obviously, I could include an if n and candidate>=n: break
in the for
loop but I'm mostly interested in why the if n: return
construct doesn't work like I'm expecting it should. Shouldn't it just return the same takewhile
iterator that works above? What am I overlooking here?
import itertools as it
def get_primes(n=None):
"""
Generates primes to a max of n.
>>> list(get_primes(100))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
"""
if n:
return it.takewhile(lambda x: x < n, get_primes())
composites = {}
yield 2
for candidate in it.count(3, 2):
prime_factor = composites.pop(candidate, None)
if prime_factor is None:
yield candidate
composites[candidate**2] = candidate
else:
composite = candidate + 2*prime_factor
while composite in composites:
composite += 2*prime_factor
composites[composite] = prime_factor
Upvotes: 5
Views: 3532
Reputation: 116
The problem is with the line
return it.takewhile(lambda x: x < n, get_primes())
Since it's a generator, returning something stops the execution, and raises StopIteration(). You need to return the values in generator
#return all the values from generator
for a in it.takewhile(lambda x: x < n, get_primes())
yield a
return
Upvotes: 2
Reputation: 500437
Here:
return it.takewhile(lambda x: x < n, get_primes())
Since this is a generator, it needs to yield
these values instead of return
ing them. Depending on your Python version, you might be able to use the yield from
syntax.
The following might be useful as background reading: Return in generator together with yield in Python 3.3
Upvotes: 3