I want to change the behavior of the generator below so that it only yields even numbers. How can I do this?
I'm aware that there simpler, clever ways to do this. This is a contrived HR challenge, where the
The change_generator
function that I wrote does not yield the desired output. I can only change change_generator
.
I cannot change positive_integers_generator()
nor the for loop below.
Can I solve this with a decorator?
#can't change the body of this function
def positive_integers_generator():
n = 1
while True:
x = yield n
if x is not None:
n = x
else:
n += 1
# can only change this function
def change_generator(generator, n):
for i in generator:
if i%2 == 0:
yield(i)
# can't change this code either
# should print 1, 2, 4, 6, 8
g = positive_integers_generator()
for _ in range(5):
n = next(g)
print(n)
change_generator(g, n)
You can use the built in function filter
even_numbers_generator = filter(lambda n: n % 2 == 0, positive_integers_generator())
Or a generator expression.
even_numbers_generator = (n for n in positive_integers_generator() if n % 2 == 0)
Or itertools.count
from the standard library:
even_numbers_generator = itertools.count(start=2, step=2)
But if you only can change the change_generator
function, the "correct answer" to the challenge probably involves using generator.send()
# can only change this function
def change_generator(generator, n):
if n % 2 == 0:
generator.send(n + 1)
You don't need the parens on generator in your loop, and you don't seem to be printing the output of the right generator. Updated version that works for me:
def positive_integers_generator():
n = 1
while True:
x = yield n
if x is not None:
n = x
else:
n += 1
def change_generator(generator):
for i in generator:
if i%2 == 0:
yield i
g = positive_integers_generator()
# should print 1, 2, 4
for _ in range(5):
n = next(change_generator(g))
print(n)
In your very specific problem, if you can't change the print(n)
part then you are pretty cornered because you can't change the instance of generator g
that was created for positive_integers_generator()
.
In what may be a frowned upon answer, in this particular case you might want to update the global g
to be reassigned to a new generator
after that:
def change_generator(generator, n):
def even_gen():
n = 2
while True:
if n % 2 == 0:
yield n
else:
yield
n += 1
global g # directly change the g referenced in main code
if not g.__name__ == 'even_gen': # change g if it is not even_gen
g = even_gen()
# output:
# 1
# 2
# None
# 4
# None