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

假设我有两个方法:

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

def method2(self):
    ...

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


当前回答

我找到了一种方法,如果你要跨越类,并且想要方法所属的类和方法。这需要一些提取工作,但它是有意义的。这在Python 2.7.13中有效。

import inspect, os

class ClassOne:
    def method1(self):
        classtwoObj.method2()

class ClassTwo:
    def method2(self):
        curframe = inspect.currentframe()
        calframe = inspect.getouterframes(curframe, 4)
        print '\nI was called from', calframe[1][3], \
        'in', calframe[1][4][0][6: -2]

# create objects to access class methods
classoneObj = ClassOne()
classtwoObj = ClassTwo()

# start the program
os.system('cls')
classoneObj.method1()

其他回答

检查。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。

您可以使用装饰器,而不必使用stacktrace

如果您想在类中修饰一个方法

import functools

# outside ur class
def printOuterFunctionName(func):
@functools.wraps(func)
def wrapper(self):
    print(f'Function Name is: {func.__name__}')
    func(self)    
return wrapper 

class A:
  @printOuterFunctionName
  def foo():
    pass

你可以删除functools, self,如果它是过程性的

较短的版本:

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