0
def countDown(i):
    if i<> 0:
        For j in countDown( i - 1 ):
            yield j
        yield i                 
if __name__ == '__main__':

    for k in countDown(5):
        print k
        if k == 6 : break

On debugging this code , the execution path was bit different from what I expected. My expectation: The "for" loop in countDown will call the function recursively: countDown(4), countDown(3), countDown(2) , and countDown(1) and countDown(0). At this point the if condition is not satisfied then the "return phase" starts, Yield j will be executed . This will return the control back to for loop in "main" function.

The next iteration of this for loop , again calls countDown(5) which starts where the last Yield left off - Yield j. This executes the for ... countdown(i-1) loop, and calls countDown(4), countDown(3) , CountDown(2).. countDown(0). Then the "return phase" begins and hit the first Yield j( j is now incremented from the first pass earlier). This will return the control back to the for loop in the "main" function.

On debug, this is what I found:

1)once it fails if i<>0 as explained in at the end of recursion, it seems to execute Yield i. Then it seems to Pop out every countDown in Stack before the control goes back to for k ... main.

2) in the Second iteration For k in g , stack enters return phase - top to botom of the stack is countDown(1) ,countDown(2),countDown(3), countDown(4) then it starts "return phase". In this phase j has the value of '1'. So. how come it does not go down to countDown(0) where i = 1 before starting the return phase?

Can anyone please explains the how this is supposed to work - combination of recursion and Generator function? Sorry for the long windy post- had no other way to explain it

Thx. guys for the reply.

My understanding so far :

1) first iteration of for k in countDown(5): entry

Function Instruction

======== ===========
countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)

countDown(1) for j in countDown(0)

countDown(0) If statement fails and returns nothing

return phase

a)

countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)

CountDown(1) for j in countDown(0)= nothing - since countDown(0) returns nothing (because of failed if condition), j has nothing annd hence yield j, does not get excuted(Yield j is within the For loop). But, Yield i gets executed ,i here is 1 . So countdown(1) returns 1 to the previous recursion.

b) countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)= 1. The value of j is now '1'. SO, the For j in countdown(1) is true . Hence, it excutes Yield j = 1. As a result countDown(2) returns 1 This is where j gets assigned i.

c) countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)= 1 The value of j is now '1'. SO, the For j in countdown(2) is true . Hence, it excutes Yield j = 1. As a result countDown(3) returns 1

...

e) Countdown(5) for j in countDown(4) = 1 The value returned by count Down(4) is 1 . Hence, j is 1. So, the for j in countDown(4) gets executed.

               The next statement Yield j  within the For statement gets exceuted.
                it returns 1.

for k in countDow(5) , k will get 1.This will be printed out.

2)Now to the second iteration of for k in countDown(5)

recursion "Entry"

=================

countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2) where j = 1

countdown(2) for j in countDown(1) where j = 1

countdown(1) executes Yield i , since the previous iteration, step a) yield was the last statement exceuted

recursion return

a) countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2) where j = 1

countdown(2) for j in countDown(1) where j = 1 Countdown(1) returns a value of 1, j already has a value of 1, so, it executes next step which is yield i where i = 2. countDown(2) returns yield i = 2

b) countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2)
since countDown(2) returns 2, j gets this new value j = 2 yield j gets executed c)

countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1 since countdown(3) returns a value of 2 as shown in b) the new value of j is 2

...

e) countdown(5) for j in countDown(4) j becomes 2

4
  • @user848798: Please fix your indentation. It's very hard to read this - use 4 spaces for each level of indent. Commented Aug 4, 2011 at 1:21
  • I tried posting it and I was getting your code is not in the correct format. So, I was left with 2 options: ask the question and ask how it is supposed to work or try adding the details and keep getting the error " your code is not formatted correct" . Initially, I thought the error message is for the the code that I put above, I kept hitting the Curly braces{} on the toolbar to correct the code format and got the same error message. Commented Aug 4, 2011 at 1:23
  • I took out the expectation part, and then I was able to post my question. I will try again to edit the question and add the descriptive part, hopefully this time I will have better luck Commented Aug 4, 2011 at 1:24
  • Never use <> in Python, use !=. Commented Aug 4, 2011 at 11:57

3 Answers 3

2

Maybe this will clarify the order in which the calls/yields occur:

Edit:

def countDown(i):
    if i<> 0:
        for j in countDown( i - 1 ):
            yield 'inner : ' + str(j)
        yield 'outer : ' + str(i)   

>>> for k in countDown(5): print k
... 
inner : inner : inner : inner : outer : 1
inner : inner : inner : outer : 2
inner : inner : outer : 3
inner : outer : 4
outer : 5

It pushes in all the way until i is 0, which doesn't yield anything, so neither does the for loop in countDown(1). countDown(1) next yields 1, which returns back to be yielded by countDown(2), countDown(3), countDown(4), and countDown(5). In other words, the yielded value returns to the previous caller, where it is yielded again and again until the call stack is unwound. The next generator to be exhausted is countDown(2), which yields 2 back to countDown(3), countDown(4), and countDown(5). The generators exhaust in succession until at last countDown(5) yields 5.

Sign up to request clarification or add additional context in comments.

3 Comments

Yield I is within the If block , not on the same level in my code
def countdown(i): if i<> 0: for j in countdown( i - 1 ): yield j yield i
,Sorry, I did not completely follow you here a) "Past the for loop yields 1 from the countDown(1) call, ..... the successive for loops for i=2, i=3, i=4, and i=5" . countDown(1) on the way down executed"For statement" to fetch countDown(0), in the return phase of countDown(1) should it not execute Yield j-which is the next statement after for loop, yield i? b) "It next turns to the countDown(2) call which yields 2 to the loops for i=3, i=4, and i=5".Is countDown(2) typo? the outer for in main callscountDown(5)
1

Let's say you iterate over countDown(5):

  1. countDown(5) fetch next countDown(4)
  2. countDown(4) fetch next countDown(3)
  3. countDown(3) fetch next countDown(2)
  4. countDown(2) fetch next countDown(1)
  5. countDown(1) fetch next countDown(0)
  6. countDown(0) yield i = 0, countDown(0) stop
  7. countDown(1) yield j = 0
  8. countDown(2) yield j = 0
  9. countDown(3) yield j = 0
  10. countDown(4) yield j = 0
  11. countDown(5) yield j = 0
  12. countDown(5) fetch next countDown(4)
  13. countDown(4) fetch next countDown(3)
  14. countDown(3) fetch next countDown(2)
  15. countDown(2) fetch next countDown(1)
  16. countDown(1) yield i = 1, countDown(1) stop
  17. countDown(2) yield j = 1
  18. countDown(3) yield j = 1
  19. countDown(4) yield j = 1
  20. countDown(5) yield j = 1
  21. countDown(5) fetch next countDown(4)
  22. countDown(4) fetch next countDown(3)
  23. countDown(3) fetch next countDown(2)
  24. countDown(2) yield i = 2, countDown(2) stop
  25. countDown(3) yield j = 2
  26. countDown(4) yield j = 2
  27. countDown(5) yield j = 2
  28. countDown(5) fetch next countDown(4)
  29. countDown(4) fetch next countDown(3)
  30. countDown(3) yield i = 3, countDown(3) stop
  31. countDown(4) yield j = 3
  32. countDown(5) yield j = 3
  33. countDown(5) fetch next countDown(4)
  34. countDown(4) yield i = 4, countDown(4) stop
  35. countDown(5) yield j = 4
  36. countDown(5) yield i = 5, countDown(5) stop

Don't know why I couldn't edit your post.

def countDown(i):
    if i <> 0:
        For j in countDown( i - 1 ):
            yield j
    yield i

It seems you just want count down, so yield i first. Then you will get 4 3 2 1 0 instead of 0 1 2 3 4

def countDown(i):
    yield i
    if i <> 0:
        For j in countDown( i - 1 ):
            yield j

2 Comments

I am not trying to countdown. I was trying to figure out how recursion and generator fucnction works together. I just happened to give the name "countDown"
,thx for the explanation. At 6) shouldn't it be countDown(0) . Stop? and 7) seems to execute countDown(1), yield i= 1. Also , 16,24 and 30 seems to be where the recursion entry stops , why does it stop at countDown(1), countDown(2), CountDown(3) instead of countDown(0) as in step 6? Also, how does the J get incremented to 2, 3, 4, 5 in steps 25, 31 and 35
0

Thx. guys for the reply.

After further debug :

1) first iteration - for k in countDown(5):

recursion entry phase

Function Instruction

======== ===========
countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)

countDown(1) for j in countDown(0)

countDown(0) If statement fails and returns nothing

recursion return phase

a)

countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)

CountDown(1) for j in countDown(0)= nothing - since countDown(0) returns nothing (because of failed if condition), j has nothing annd hence yield j, does not get excuted(Yield j is within the For loop). But, Yield i gets executed ,i here is 1 . So countdown(1) returns 1 to the previous recursion.

b) countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)

countDown(2) for j in countDown(1)= 1. The value of j is now '1'. SO, the For j in countdown(1) is true . Hence, it excutes Yield j = 1. As a result countDown(2) returns 1 This is where j gets assigned i.

c) countdown(5) for j in countDown(4)

countdown(4) for j in countDown(3)

countDown(3) for j in countDown (2)= 1 The value of j is now '1'. SO, the For j in countdown(2) is true . Hence, it excutes Yield j = 1. As a result countDown(3) returns 1

...

e) Countdown(5) for j in countDown(4) = 1 The value returned by count Down(4) is 1 . Hence, j is 1. So, the for j in countDown(4) gets executed.

               The next statement Yield j  within the For statement gets exceuted.
                it returns 1.

for k in countDow(5) , k will get 1.This will be printed out.

2)Now to the second iteration - for k in countDown(5)

recursion entry phase

countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2) where j = 1

countdown(2) for j in countDown(1) where j = 1

countdown(1) executes Yield i , since the previous iteration, step a) yield was the last statement exceuted

recursion return

a) countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2) where j = 1

countdown(2) for j in countDown(1) where j = 1 Countdown(1) returns a value of 1, j already has a value of 1, so, it executes next step which is yield i where i = 2. countDown(2) returns yield i = 2

b) countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1

countDown(3) for j in countDown (2)
since countDown(2) returns 2, j gets this new value j = 2 yield j gets executed c)

countdown(5) for j in countDown(4) where j = 1 (Yield j was the last statement executed)

countdown(4) for j in countDown(3) where j = 1 since countdown(3) returns a value of 2 as shown in b) the new value of j is 2

...

e) countdown(5) for j in countDown(4) j becomes 2

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.