Tracing Functions in Python

DateReadtime 2 minutes Tags

Sometimes I want to debug the inputs and outputs of function calls to visualize flow or to follow execution passively.

Rather than adding logging statements and littering them around the code, a single decorator can be crafted to show the life cycle of a function:

def trace_args(f):
    def wrapper(*args):
        print "%s(%s)" % (f.__name__, ", ".join(str(arg) for arg in args))
        ret = f(*args)
        print "%s(%s) => %s" % (f.__name__, ", ".join(str(arg) for arg in args), ret)
        return ret
    return wrapper

An example, given a function sum like the following:

def sum(a, b):
    return a + b

>>> sum(1, 3)
4

Applying the decorator would look like this:

@trace_args
def sum(a, b):
    return a + b

>>> sum(1, 4)
sum(1, 4)
sum(1, 4) => 5
5

Slightly more complicated example:

@trace_args
def sum(a, b):
    return a + b

@trace_args
def add_five(a):
    return sum(a, 5)

>>> add_five(4)
add_five(4)
sum(4, 5)
sum(4, 5) => 9
add_five(4) => 9
5

Use the following example to simply display the type of the input and outputs

def trace_args(f):
    def wrapper(*args):
        print "%s(%s)" % (f.__name__, ", ".join(str(type(arg)) for arg in args))
        ret = f(*args)
        print "%s(%s) => %s" % (f.__name__, ", ".join(str(type(arg)) for arg in args), str(type(ret)))
        return ret
    return wrapper