Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I print functions as they are called

In debugging a Python script, I'd really like to know the entire call stack for my entire program. An ideal situation would be if there were a command-line flag for python that would cause Python to print all function names as they are called (I checked man Python2.7, but didn't find anything of this sort).

Because of the number of functions in this script, I'd prefer not to add a print statement to the beginning of each function and/or class, if possible.

An intermediate solution would be to use PyDev's debugger, place a couple breakpoints and check the call stack for given points in my program, so I'll use this approach for the time being.

I'd still prefer to see a complete list of all functions called throughout the life of the program, if such a method exists.

like image 400
James Avatar asked Nov 29 '11 17:11

James


People also ask

Can you call a function in a print statement?

Yes, it does. The return value is what will print. Yes but as a “call” they aren't asking for a call in the context of a print function, they want you to “call” the defined parent function “calculate_age()”… As noted above, print(calculate_age(1970)) absolutely does involve a function call.

What is print function called in Python?

Python print() Function The print() function prints the specified message to the screen, or other standard output device. The message can be a string, or any other object, the object will be converted into a string before written to the screen.


2 Answers

You can do this with a trace function (props to Spacedman for improving the original version of this to trace returns and use some nice indenting):

def tracefunc(frame, event, arg, indent=[0]):       if event == "call":           indent[0] += 2           print("-" * indent[0] + "> call function", frame.f_code.co_name)       elif event == "return":           print("<" + "-" * indent[0], "exit function", frame.f_code.co_name)           indent[0] -= 2       return tracefunc  import sys sys.setprofile(tracefunc)  main()   # or whatever kicks off your script 

Note that a function's code object usually has the same name as the associated function, but not always, since functions can be created dynamically. Unfortunately, Python doesn't track the function objects on the stack (I've sometimes fantasized about submitting a patch for this). Still, this is certainly "good enough" in most cases.

If this becomes an issue, you could extract the "real" function name from the source code—Python does track the filename and line number—or ask the garbage collector find out which function object refers to the code object. There could be more than one function sharing the code object, but any of their names might be good enough.

Coming back to revisit this four years later, it behooves me to mention that in Python 2.6 and later, you can get better performance by using sys.setprofile() rather than sys.settrace(). The same trace function can be used; it's just that the profile function is called only when a function is entered or exited, so what's inside the function executes at full speed.

like image 50
kindall Avatar answered Oct 06 '22 01:10

kindall


Another good tool to be aware of is the trace module. There are 3 options of showing function names.

Example foo.py:

def foo():    bar()  def bar():    print("in bar!")  foo() 
  1. Using -l/--listfuncs to list funtions:
$ python -m trace --listfuncs foo.py in bar!  functions called: filename: /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/trace.py, modulename: trace, funcname: _unsettrace filename: foo.py, modulename: foo, funcname: <module> filename: foo.py, modulename: foo, funcname: bar filename: foo.py, modulename: foo, funcname: foo 
  1. Using -t/--trace to list lines as they are executed.
$python -m trace --trace foo.py  --- modulename: foo, funcname: <module> foo.py(1): def foo(): foo.py(4): def bar(): foo.py(7): foo()  --- modulename: foo, funcname: foo foo.py(2):    bar()  --- modulename: foo, funcname: bar foo.py(5):    print("in bar!") in bar! 
  1. Using -T/--trackcalls to list what calls what
$ python -m trace --trackcalls foo.py in bar!  calling relationships:  *** /usr/lib/python3.8/trace.py ***   --> foo.py     trace.Trace.runctx -> foo.<module>  *** foo.py ***     foo.<module> -> foo.foo     foo.foo -> foo.bar 
like image 20
David Wolever Avatar answered Oct 06 '22 00:10

David Wolever