Let me try:
From your snippet, in every function call i.e foo(step+1) a structure known as an activation record or
frame is created to store information about the progress of that invocation of the function.
So, When the execution of a function leads to a nested function call, the execution of the former call
is suspended and its activation record stores the place in the source code at which the flow of control
should continue upon return of the nested call.
Here is the main part:
When step == 4, which in turns range(4,4) == empty list, that time iteration won't happen so it will return
None. Then it will move to the previous frame, where it was stopped and start a new iteration and recursive function call
until range(4,4).
NB: Recursive base case is only when step == 4, that time range(4,4) and return None.
Every recusion needs a base case other wise it will goto infinite loop.
So, lets see the recursive trace: I am adding i to differentiate the step and iterative increment.
# 1 def foo(step=0):
# 2 for i in range(step, 4):
# 3 print 'i: %d, step: %d' % (i,step)
# 4 foo(step+1)
# 5 foo()
line 5
line 1 foo with step=0 which is default
line 2 range(0,4) Frame: A, 0 is over, next=1
line 3 step = 0 Output: i: 0, step: 0
line 4 calling foo(0 + 1)
line 1 foo with step=1
line 2 range(1,4) Frame: B, 1 is over, next=2
line 3 step = 1 Output: i: 1, step: 1
line 4 calling foo(1 + 1)
line 1 foo with step=2
line 2 range(2,4) Frame: C, 2 is over, next=3
line 3 step = 2 Output: i: 2, step: 2
line 4 calling foo(2 + 1)
line 1 foo with step=3
line 2 range(3,4) Frame: D, 3 is over, next=4
line 3 step = 3, Output: i: 3, step: 3
line 4 calling foo(3 + 1)
line 1 foo with step=4
line 2 range(4,4) Frame: E,
This is an empty list, so it won't come inside the loop, so return None.
Come back to previous Frame: D, i=3 was used, now increment to 4. So, again range(4,4)
line 2 range(4,4) Empty list, from Frame: D, return None
Come back to previous Frame C, now i=3, step was called with value 2
line 2 range(2,4)
line 3 step = 2 Output: i: 3, step: 2, why step == 2 because the function foo was called with step=2
line 4 calling foo(2 + 1)
line 1 foo with step=3
line 2 range(3,4)
line 3 step = 3, Output : i: 3, step: 3
line 4 calling foo(3 + 1)
line 1 foo with step=4
line 2 range(4,4) Empty list again, not going inside the list, return None
line 2 range(2,4) From Frame: B, step was == 1, because the function foo was called with step=1
line 3 step: 1 Output: i: 2, step: 1, here i ==2, because this is the second iteration of Frame B.
line 4 calling foo(1 + 1)
line 1 foo with step=2
line 2 range(2,4)
line 3 step: 2 Output: i: 2, step: 2
After this it follows the same recursive fashion, until the iterative range is exhuausted i.e range(4,4)
Please let me know if that helps.
print range(step, 4)before the for loop.