Reputation: 765
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
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
Upvotes: 0
Views: 567
Reputation: 765
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
Upvotes: 0
Reputation: 34270
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.
Upvotes: 2
Reputation: 10653
Let's say you iterate over countDown(5)
:
countDown(5)
fetch next countDown(4)
countDown(4)
fetch next countDown(3)
countDown(3)
fetch next countDown(2)
countDown(2)
fetch next countDown(1)
countDown(1)
fetch next countDown(0)
countDown(0)
yield i
= 0, countDown(0)
stopcountDown(1)
yield j
= 0countDown(2)
yield j
= 0countDown(3)
yield j
= 0countDown(4)
yield j
= 0countDown(5)
yield j
= 0countDown(5)
fetch next countDown(4)
countDown(4)
fetch next countDown(3)
countDown(3)
fetch next countDown(2)
countDown(2)
fetch next countDown(1)
countDown(1)
yield i
= 1, countDown(1)
stopcountDown(2)
yield j
= 1countDown(3)
yield j
= 1countDown(4)
yield j
= 1countDown(5)
yield j
= 1countDown(5)
fetch next countDown(4)
countDown(4)
fetch next countDown(3)
countDown(3)
fetch next countDown(2)
countDown(2)
yield i
= 2, countDown(2)
stopcountDown(3)
yield j
= 2countDown(4)
yield j
= 2countDown(5)
yield j
= 2countDown(5)
fetch next countDown(4)
countDown(4)
fetch next countDown(3)
countDown(3)
yield i
= 3, countDown(3)
stopcountDown(4)
yield j
= 3countDown(5)
yield j
= 3countDown(5)
fetch next countDown(4)
countDown(4)
yield i
= 4, countDown(4)
stopcountDown(5)
yield j
= 4countDown(5)
yield i
= 5, countDown(5)
stopDon'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
Upvotes: 1