[Tutor] trace / profile function calls with inputs

spir denis.spir at gmail.com
Mon Feb 10 13:09:37 CET 2014


On 02/08/2014 05:36 PM, Richard Cziva wrote:
> Hi All,
>
> I am trying to print out every function that is being called while my Python
> program is running (own functions and library calls too). I can not modify the
> Python programs I am trying to profile.
>
> Let me give an example. A program contains a function like this:
>
> def foo(x):
>    y = math.cos(x)
>    z = 1 + 1
>    time.sleep(y+1)
>    return x * 50
>
> And it calls the function:
>
> print foo(100)
>
> I would like to retrieve an execution trace that shows me each function called
> with the value or hash of its arguments. According to the example, I am looking
> for a technique to extract something similar:
>
> foo(100)
> math.cos(100)
> time.sleep(0.87)
>
> Things I have tried with only partial success:
> - trace module
> - profile module / cProfile
>
> Could you suggest me a way of doing this?

You need to wrap every function call in a tracing wrapper function that (1) does 
what you want (2) calls the wrapped function. Something like this:

def trace (func, *args):
     # trace
     func_name = func.__name__
     arg_strings = (str(arg) for arg in args)
     arg_string = ", ".join(arg_strings)
     print("%s(%s)" % (func_name, arg_string))
     # call
     result = func(*args)
     if result: return result

def f (x,y):
     return (x+y) / 2
def g (x,y):
     print((x+y) / 2)

trace(g, 3, 7)
z = trace(f, 3, 7)
print(z)

==>

g(3, 7)
5.0
f(3, 7)
5.0

As you see, there is a subtility about the distinction between functions that 
_do_ something (actions, in fact) and function that compute a product (function 
properly speaking). But actually you could ignore because the former implicitely 
return none.

You cannot always have the same call expression as in the actual calling code: 
you always have the _values_. For example:
	a = 9
	y = 7
	trace(f(math.sqrt(a), y)
will show:
	f(3, 7)
Python does not let you know _the code_. You would need a "homoiconic" language 
like Lisp for that: a language in which "code is data" (data of the language 
types). In python, code is opaque, it is plain raw data (bit string) without any 
language type & value. So, I guess we cannot do much better than the above, but 
I may be wrong.

The right way to do this would in fact be using so-called "decorators". But the 
example above shows the principle (and the code you'd have to put in a decorator).

d


More information about the Tutor mailing list