使用Python从函数内部获取当前函数名称

36
我想记录下我的代码所经过的所有函数名称。无论是谁调用这些函数都无关紧要。
import inspect

def whoami():
    return inspect.stack()[1][3]

def foo():
    print(whoami())

目前它打印的是foo。我希望它打印whoami

你想调用并执行函数,还是只是调用名称?因为你现在正在做后者,在最后一行的whoami后没有括号。 - user707650
当前它打印 foo:您当前的示例代码没有输出任何内容,或者至少不会输出 foo。请编辑并提供一个有效的示例。 - starrify
2
inspect.stack()[0][3]? - lsbbo
1
你可能想要执行以下代码: print(whoami())。此外,@hero 是正确的,你应该使用 inspect.stack()[0][3] 来获取名称。 - Nir Alfasi
7个回答

56

你可能需要 inspect.getframeinfo(frame).function

import inspect

def whoami(): 
    frame = inspect.currentframe()
    return inspect.getframeinfo(frame).function

def foo():
    print(whoami())

foo()

打印

whoami

4
这个对我有用:return inspect.getouterframes(inspect.currentframe())[1].function意思是返回当前函数的调用者的函数名称。 - coder.in.me
1
同时使用 import inspect,在设置 frame = inspect.currentframe() 的同时,您可以跟随 print(frame.f_code.co_name)return frame.f_code.co_name,以提供当前函数的名称。 - Android Control
@AndroidControl 的确。正如我在我的答案中所指出的,也可以使用currentframe().f_back.f_code.co_name来获取调用函数的名称。 - Asclepius

30
实际上,如果这是关于日志记录的问题,Eric的答案指出了方向:

为了我的日志记录目的,我想记录代码执行的所有函数名称

您可以调整格式化程序以记录函数名称

import logging               

def whoami():
    logging.info("Now I'm there")

def foo():
    logging.info("I'm here")
    whoami()
    logging.info("I'm back here again")

logging.basicConfig(
    format="%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s",
    level=logging.INFO)
foo()

打印

2015-10-16 16:29:34,227 [INFO] foo: I'm here
2015-10-16 16:29:34,227 [INFO] whoami: Now I'm there
2015-10-16 16:29:34,227 [INFO] foo: I'm back here again

2
@JohnKaff:我认为你遇到了一个X/Y问题,最好提出一个新问题,询问如何在Python中记录函数调用(包括参数、类方法等)。 - Eric
这比其他任何东西都要好。 - babygame0ver

19

为了记录日志,我想记录我的代码执行过程中所有函数的名称。

您是否考虑过装饰器?

import functools
def logme(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        print(f.__name__)
        return f(*args, **kwargs)
    return wrapped


@logme
def myfunction():
    print("Doing some stuff")

1
谢谢Eric,我会尝试的。有没有办法将该装饰器应用于类的所有函数? - John Kaff
@JohnKaff:是的,你也可以将装饰器应用于类。你需要让装饰器迭代类对象的所有方法,并在这个装饰器中包装它们。 - Eric

11

调用sys._getframe()方法可以获取一个frame类的实例。其中,f_code.co_name成员变量保存了函数名。

sys._getframe(0).f_code.co_name

添加一个简单的帮助函数func_name()来包装调用

import sys

def func_name(): 
    return sys._getframe(1).f_code.co_name

def func1():
    print(func_name())

func1()  # prints 'func1'

7
这个简单的可重用方法返回调用者/父函数的名称:
import inspect

def current_method_name():
    # [0] is this method's frame, [1] is the parent's frame - which we want
    return inspect.stack()[1].function  

# Example:
def whoami():
    print(current_method_name())

whoami()

-> 输出结果为 whoami


1
虽然这种方法可以获取调用者的名称,但请注意inspect.stack被认为是慢的。另一种选择是使用inspect.currentframe().f_back.f_code.co_name,就像这个答案中所示。 - Asclepius

1
在这里添加一个答案,因为包含类名和函数可能很有用。
这将检查self和cls约定,以包括类名。
def name_of_caller(frame=1):
    """
    Return "class.function_name" of the caller or just "function_name".
    """
    frame = sys._getframe(frame)
    fn_name = frame.f_code.co_name
    var_names = frame.f_code.co_varnames
    if var_names:
        if var_names[0] == "self":
            self_obj = frame.f_locals.get("self")
            if self_obj is not None:
                return type(self_obj).__name__ + "." + fn_name
        if var_names[0] == "cls":
            cls_obj = frame.f_locals.get("cls")
            if cls_obj is not None:
                return cls_obj.__name__ + "." + fn_name
    return fn_name


1
这可能是最快的实现。它避免了使用额外的检查方法,这可能会很慢或不必要。
实现方式如下:
from inspect import currentframe

def get_self_name() -> str:
    return currentframe().f_code.co_name

def get_caller_name() -> str:
    return currentframe().f_back.f_code.co_name

def get_parent_caller_name() -> str:
    return currentframe().f_back.f_back.f_code.co_name

使用方法:

def actual_function_1():
    print('In actual_function_1:', get_self_name())

def actual_function_2():
    print('In actual_function_2:', get_caller_name())

def actual_function_3() -> None:
    print('In actual_function_3:', get_parent_caller_name())

actual_function_1()
actual_function_2()
actual_function_3()

输出:

In actual_function_1: get_self_name
In actual_function_2: actual_function_2
In actual_function_3: <module>

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