Get function callers' information in python

折月煮酒 提交于 2019-11-30 13:21:27

Yes, the sys._getframe() function let's you retrieve frames from the current execution stack, which you can then inspect with the methods and documentation found in the inspect module; you'll be looking for specific locals in the f_locals attribute, as well as for the f_code information:

import sys
def special_func(x):
    callingframe = sys._getframe(1)
    print 'My caller is the %r function in a %r class' % (
        callingframe.f_code.co_name, 
        callingframe.f_locals['self'].__class__.__name__)

Note that you'll need to take some care to detect what kind of information you find in each frame.

sys._getframe() returns a frame object, you can chain through the whole stack by following the f_back reference on each. Or you can use the inspect.stack() function to produce a lists of frames with additional information.

An example:

def f1(a):
    import inspect
    print 'I am f1 and was called by', inspect.currentframe().f_back.f_code.co_name
    return a

def f2(a):
    return f1(a)

Will retrieve the "immediate" caller.

>>> f2(1)
I am f1 and was called by f2

And if wasn't called from another you get (in IDLE):

>>> f1(1)
I am f1 and was called by <module>

Thanks to Jon Clements answer I was able to make a function that returns an ordered list of all callers:

def f1():
    names = []
    frame = inspect.currentframe()
    ## Keep moving to next outer frame
    while True:
        try:
            frame = frame.f_back
            name = frame.f_code.co_name
            names.append(name)
        except:
            break
    return names

and when called in a chain:

def f2():
    return f1()

def f3():
    return f2()

def f4():
    return f3()

print f4()

looks like this:

['f2', 'f3', 'f4', '<module>']

In my case I filter out anything at '<module>' and after, and then take the last item to be the name of the originating caller.

Or modify the original loop to bail at the first appearance of any name starting with '<':

frame = frame.f_back
name = frame.f_code.co_name
if name[0] == '<':
    break
names.append(name)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!