Yield usage in recursive manner

I was playing around with the yield and I made up a function that takes 3 numbers and a limit and computes them in a particular way (the computation is not important, but can be seen in the code below).

values = []

def compute(limit, a, b, c):
    if a <= limit:
        print("Got {}, {}, {}".format(a, b, c))
        values.append([a, b, c])
        compute(limit, b*c, a*c, a*b)
    else:
        print("Process ended")


compute(9999, 2, 3, 4)
print(values)

This works, and produces the output:

Got 2, 3, 4
Got 12, 8, 6
Got 48, 72, 96
Got 6912, 4608, 3456
Process ended
[[2, 3, 4], [12, 8, 6], [48, 72, 96], [6912, 4608, 3456]]

However, I am sure that this can be done with the usage of yield - mainly the values list creation part, which, as you see, is filled manually by me in the function.

The reason why I bother at all is just why the yield is used in the first place - here it doesn't matter, but what if my task required the 100000th value from this list - constructing it as a whole is not required, or even plainly stupid considering I don't want the previous 99999 values...

I tried using something like:

def compute_y(a, b, c):
    while True:
        yield b*c, a*c, b*a

for a, b, c in compute_y(2, 3, 4):
    if a > 9999:
        break

The problem with this is that the numbers in the for are the same all the time (2, 3 and 4), so it's never gonna reach other values and because of that it's an infinite loop.

tl;dr - can I use yield here at all to make the algorithm more efficient for bigger lists?

2 answers

  • answered 2018-05-21 13:26 Ry-

    Yep, you’ll need to assign the new values for the next loop iteration:

    def compute_y(a, b, c):
        while True:
            yield a, b, c
            a, b, c = b*c, a*c, b*a
    

  • answered 2018-05-21 13:33 Sqoshu

    Okay, the whole problem was caused of me thinking that yield works similar to return not caring about the latter lines after yield.

    The whole thing using yield (with the hint given by Ry-) works like this:

    def compute_y(a, b, c):
        while True:
            yield a, b, c
            a, b, c = b*c, a*c, b*a
    
    
    for a, b, c in compute_y(2, 3, 4):
        if a < 9999:
            print(a, b, c)
        else:
            break
    

    Output:

    2 3 4
    12 8 6
    48 72 96
    6912 4608 3456