在Python中获取函数调用者的信息

8
我想获取Python中特定函数的调用者信息。例如:
class SomeClass():
    def __init__(self, x):
        self.x = x
    def caller(self):
        return special_func(self.x)

def special_func(x):
    print "My caller is the 'caller' function in an 'SomeClass' class."

用Python可以实现吗?

3个回答

14

是的,sys._getframe() 函数可以让你从当前执行栈中检索帧(frame),然后你可以使用 inspect 模块 中的方法和文档进行检查;你将会在 f_locals 属性中查找特定的本地变量,并查看 f_code 信息:

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__)
请注意,您需要小心检测每个帧中包含的信息类型。 sys._getframe()返回一个帧对象,您可以通过在每个帧上跟随f_back引用来链接整个堆栈。或者您可以使用inspect.stack()函数生成一个带有额外信息的帧列表。

3
文档中写道:“在所有 Python 实现中都不能保证它的存在。” - pradyunsg

3
一个例子:
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)

将检索“立即”调用者。
>>> f2(1)
I am f1 and was called by f2

如果该函数未从其他函数中调用,则在IDLE中会得到以下结果:

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

谢谢,我能够将这个内容适应到我的需求中。 - Zach Young

2
感谢Jon Clements的答案,我能够制作一个返回所有调用者有序列表的函数:
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

当在一个链式调用中被调用时:

def f2():
    return f1()

def f3():
    return f2()

def f4():
    return f3()

print f4()

看起来是这样的:

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

在我的情况下,我过滤掉任何位于 '<module>' 之后的内容,然后将最后一个项目视为调用者名称。

或者修改原始循环,在出现以 '<' 开头的任何名称时停止循环:

frame = frame.f_back
name = frame.f_code.co_name
if name[0] == '<':
    break
names.append(name)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接