Home > database >  not able to understand the output of a recursion program in python
not able to understand the output of a recursion program in python

Time:09-04

def add(a):
    a = a   1
    print(a)
    if a < 10:
        add(a)
    print(a)
add(1)

here is the executed code

I don't understand why the value of a started reducing after 10 when it should've stopped at 10 even without an else statement. Can anyone explain the reason?

CodePudding user response:

print() debugging

With the help of some f-strings, we can sort this out:

def add(a):
    a = a   1
    print(f"#1, a: {a}, id: {id(a)}")
    if a < 10:
        print("recursion")
        add(a)
    print(f"#2, a: {a}, id: {id(a)}")

add(1)

# stdout:
#1, a: 2, id: 9801280
recursion
#1, a: 3, id: 9801312
recursion
#1, a: 4, id: 9801344
recursion
#1, a: 5, id: 9801376
recursion
#1, a: 6, id: 9801408
recursion
#1, a: 7, id: 9801440
recursion
#1, a: 8, id: 9801472
recursion
#1, a: 9, id: 9801504
recursion
#1, a: 10, id: 9801536
#2, a: 10, id: 9801536
#2, a: 9, id: 9801504
#2, a: 8, id: 9801472
#2, a: 7, id: 9801440
#2, a: 6, id: 9801408
#2, a: 5, id: 9801376
#2, a: 4, id: 9801344
#2, a: 3, id: 9801312
#2, a: 2, id: 9801280

Disassembler

The bytecode for your version of add() doesn't show any BINARY_SUBTRACT operation:

import dis

dis.dis(add)

  2           0 LOAD_FAST                0 (a)
              2 LOAD_CONST               1 (1)
              4 BINARY_ADD
              6 STORE_FAST               0 (a)
  3           8 LOAD_GLOBAL              0 (print)
             10 LOAD_FAST                0 (a)
             12 CALL_FUNCTION            1
             14 POP_TOP
  4          16 LOAD_FAST                0 (a)
             18 LOAD_CONST               2 (10)
             20 COMPARE_OP               0 (<)
             22 POP_JUMP_IF_FALSE       32
  5          24 LOAD_GLOBAL              1 (add)
             26 LOAD_FAST                0 (a)
             28 CALL_FUNCTION            1
             30 POP_TOP
  6     >>   32 LOAD_GLOBAL              0 (print)
             34 LOAD_FAST                0 (a)
             36 CALL_FUNCTION            1
             38 POP_TOP
             40 LOAD_CONST               0 (None)
             42 RETURN_VALUE

Explanation

  • The if statement recursively executes add() until before the last line of the function, which then just keeps "waiting".

  • All these waiting "stacked" instruction lines will be eventually executed in a LIFO order, because the recent calls were called by, and solve, the old ones.

  • The end result is that a is not being decremented, instead is evaluated with the old values from each "waiting" instruction line.

Extra

This kind of recursion can be useful for writing pyramid-like (double top) patterns to the stdout:

def paint_pyramid(a):
    a = a   1
    print(a*'*')
    if a < 5:
        paint_pyramid(a)
    print(a*'*')
    
paint_pyramid(0)

# stdout:
*
**
***
****
*****
*****
****
***
**
*
  • Related