如何在被调用的方法中获得调用者的方法名?

假设我有两个方法:

def method1(self):
    ...
    a = A.method2()

def method2(self):
    ...

如果我不想为method1做任何改变,如何获得调用者的名字(在这个例子中,名字是method1)在method2?


当前回答

代码:

#!/usr/bin/env python
import inspect

called=lambda: inspect.stack()[1][3]

def caller1():
    print "inside: ",called()

def caller2():
    print "inside: ",called()
    
if __name__=='__main__':
    caller1()
    caller2()

输出:

shahid@shahid-VirtualBox:~/Documents$ python test_func.py 
inside:  caller1
inside:  caller2
shahid@shahid-VirtualBox:~/Documents$

其他回答

检查。Getframeinfo和inspect中的其他相关函数可以帮助:

>>> import inspect
>>> def f1(): f2()
... 
>>> def f2():
...   curframe = inspect.currentframe()
...   calframe = inspect.getouterframes(curframe, 2)
...   print('caller name:', calframe[1][3])
... 
>>> f1()
caller name: f1

这种内省旨在帮助调试和开发;出于生产功能的目的而依赖它是不可取的。

我将使用inspect.currentframe().f_back.f_code.co_name。它的用法在之前的回答中没有涉及,主要有三种类型:

一些先前的答案使用inspect。堆栈,但它是众所周知的太慢。 一些先前的回答使用sys。_getframe是一个内部私有函数,因为它有前导下划线,所以不鼓励使用它。 一个先前的答案使用inspect.getouterframes(inspect.currentframe(), 2)[1][3],但它完全不清楚[1][3]正在访问什么。

import inspect
from types import FrameType
from typing import cast


def demo_the_caller_name() -> str:
    """Return the calling function's name."""
    # Ref: https://stackoverflow.com/a/57712700/
    return cast(FrameType, cast(FrameType, inspect.currentframe()).f_back).f_code.co_name


if __name__ == '__main__':
    def _test_caller_name() -> None:
        assert demo_the_caller_name() == '_test_caller_name'
    _test_caller_name()

注意cast(FrameType, frame)是用来满足mypy的。


致谢:回复请留言1313e。

嘿,伙计,我曾经为我的应用程序做了3个没有插件的方法,也许这可以帮助你,它对我有用,所以可能对你也有用。

def method_1(a=""):
    if a == "method_2":
        print("method_2")

    if a == "method_3":
        print("method_3")


def method_2():
    method_1("method_2")


def method_3():
    method_1("method_3")


method_2()

较短的版本:

import inspect

def f1(): f2()

def f2():
    print 'caller name:', inspect.stack()[1][3]

f1()

(感谢@Alex和Stefaan Lippen)

Python的Logging库使用sys._getframe()的替代方法来查找调用者信息。这个想法是这样的:

引发一个异常 立即在Except子句中捕获它 使用系统。获取Traceback帧(tb_frame)。 从tb_frame使用f_back获取上一个调用者的帧。 从上一个调用者的帧中获取在该帧中执行的代码对象。 在我们的示例代码中,执行的是method1(不是method2)。 从获得的代码对象中,获取对象的名称——这是示例中调用者方法的名称。

下面是解决问题的示例代码:

def method1():
    method2()

def method2():
    try:
        raise Exception
    except Exception:
        frame = sys.exc_info()[2].tb_frame.f_back

    print("method2 invoked by: ", frame.f_code.co_name)

# Invoking method1
method1()

输出:

method2 invoked by: method1

Frame有各种各样的细节,包括行号、文件名、参数计数、参数类型等等。该解决方案也可以跨类和模块工作。