While browsing some Python posts on the Net, I saw one that made use of the sys._getframe() function. I had seen that function before, and remembered that it returns information about currently active stack frames. So I looked up the docs for sys._getframe(), thinking that it might be possible to use it within a function, to find that function's caller. Turned out that it could. I also googled for terms like "find the name of the calling function in python", and found two relevant Stack Overflow (SO) posts:
Getting the caller function name inside another function in Python?
Python: How to get the caller's method name in the called method?
It can be done by using either inspect.stack() or sys._getframe(). (The inspect module in Python's standard library supports that (finding a function's caller via stack frames), as well as some other useful introspection techniques.)
(I had blogged a couple of times about inspect, earlier, here:
Python's inspect module is powerful
and here:
Using inspect.getargvalues to debug Python programs
)
So I tried out the SO code examples and slightly modified them to make these two small programs that print the name of the caller, and the caller's caller.
Here is the first program:
''' File: find_callers.py Run with: python find_callers.py ''' import sys def foo(): print "I am foo, calling bar:" bar() def bar(): print "I am bar, calling baz:" baz() def baz(): print "I am baz:" caller = sys._getframe(1).f_code.co_name callers_caller = sys._getframe(2).f_code.co_name print "I was called from", caller print caller, "was called from", callers_caller foo()When run, this program outputs:
I am foo, calling bar: I am bar, calling baz: I am baz: I was called from bar bar was called from foo
The second program is similar to the one above, except that, just for fun and to do it differently, I defined part of the overall code expression as a string, interpolated the argument (2 or 3) into it using Python string formatting, and then eval()'ed the resulting string. Note that since there is now an additional function call (eval), I had to change the arguments to sys._getframe() from 1 and 2 to 2 and 3:
# File: find_callers_with_eval.py # Run with: python find_callers_with_eval.py import sys getframe_expr = 'sys._getframe({}).f_code.co_name' def foo(): print "I am foo, calling bar:" bar() def bar(): print "I am bar, calling baz:" baz() def baz(): print "I am baz:" caller = eval(getframe_expr.format(2)) callers_caller = eval(getframe_expr.format(3)) print "I was called from", caller print caller, "was called from", callers_caller foo()The output of this second program was identical to the first.
Note that the Python documentation says:
[ CPython implementation detail: This function should be used for internal and specialized purposes only. It is not guaranteed to exist in all implementations of Python. ]
Also, use eval() with care, and only on trusted code.
- Vasudev Ram - Online Python training and programming Dancing Bison EnterprisesSignup to hear about new products and services that I create. Posts about Python Posts about xtopdf
No comments:
Post a Comment