Skip to content

Decorators

Trace recursive functions

Reference
from functools import wraps

# decorator to trace execution of recursive function
def trace(func):

    # cache func name, which will be used for trace print
    func_name = func.__name__
    # define the separator, which will indicate current recursion level (repeated N times)
    separator = '|  '

    # current recursion depth
    trace.recursion_depth = 0

    @wraps(func)
    def traced_func(*args, **kwargs):

        # repeat separator N times (where N is recursion depth)
        # `map(str, args)` prepares the iterable with str representation of positional arguments
        # `", ".join(map(str, args))` will generate comma-separated list of positional arguments
        # `"x"*5` will print `"xxxxx"` - so we can use multiplication operator to repeat separator
        print(f'{separator * trace.recursion_depth}|-- {func_name}({", ".join(map(str, args))})')
        # we're diving in
        trace.recursion_depth += 1
        result = func(*args, **kwargs)
        # going out of that level of recursion
        trace.recursion_depth -= 1
        # result is printed on the next level
        print(f'{separator * (trace.recursion_depth + 1)}`-- return {result}')

        return result

    return traced_func
Example
@trace
def accumufact(n, fact=1) :
    if n == 1: return fact
    else: return accumufact(n-1, n*fact)

@trace
def fib(n):
    if n ==0 or n == 1: return n
    return fib(n-1) + fib(n-2)

@trace
def gcd(p, q):
    if q == 0: return p
    else: return gcd(q, p %q)


def title(s):
    line = "-"*32
    print()
    print(line)
    print(s.center(32))
    print(line)
    print()

title("accumufact")
print(accumufact(7))

title("fib")
print(fib(4))

title("gcd")
print(gcd(165,27))

Output:

--------------------------------
        accumufact           
--------------------------------

|-- accumufact(7)
|  |-- accumufact(6, 7)
|  |  |-- accumufact(5, 42)
|  |  |  |-- accumufact(4, 210)
|  |  |  |  |-- accumufact(3, 840)
|  |  |  |  |  |-- accumufact(2, 2520)
|  |  |  |  |  |  |-- accumufact(1, 5040)
|  |  |  |  |  |  |  `-- return 5040
|  |  |  |  |  |  `-- return 5040
|  |  |  |  |  `-- return 5040
|  |  |  |  `-- return 5040
|  |  |  `-- return 5040
|  |  `-- return 5040
|  `-- return 5040
5040

--------------------------------
            fib               
--------------------------------

|-- fib(4)
|  |-- fib(3)
|  |  |-- fib(2)
|  |  |  |-- fib(1)
|  |  |  |  `-- return 1
|  |  |  |-- fib(0)
|  |  |  |  `-- return 0
|  |  |  `-- return 1
|  |  |-- fib(1)
|  |  |  `-- return 1
|  |  `-- return 2
|  |-- fib(2)
|  |  |-- fib(1)
|  |  |  `-- return 1
|  |  |-- fib(0)
|  |  |  `-- return 0
|  |  `-- return 1
|  `-- return 3
3

--------------------------------
            gcd               
--------------------------------

|-- gcd(165, 27)
|  |-- gcd(27, 3)
|  |  |-- gcd(3, 0)
|  |  |  `-- return 3
|  |  `-- return 3
|  `-- return 3
3