在Python中,如果不使用traceback模块,是否有一种方法可以从函数内部确定函数的名称?

假设我有一个模块foo和一个功能栏。当执行foo.bar()时,是否有一种方法让bar知道bar的名字?或者更好的是,foo。酒吧的名字吗?

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?

当前回答

import inspect

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

def whosdaddy():
    return inspect.stack()[2][3]

def foo():
    print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
    bar()

def bar():
    print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())

foo()
bar()

在IDE中,代码输出

你好,我是foo,爸爸是 你好,我是bar,爸爸是foo 你好,我是bar,爸爸是

其他回答

print(inspect.stack()[0].function)似乎也可以工作(Python 3.5)。

使用__name__属性:

# foo.py
def bar():
    print(f"my name is {bar.__name__}")

你可以使用__name__属性轻松地从函数内部访问函数名。

>>> def bar():
...     print(f"my name is {bar.__name__}")
...
>>> bar()
my name is bar

我自己也遇到过这个问题好几次,一直在寻找解决方法。正确答案包含在Python文档中(参见可调用类型部分)。

每个函数都有返回其名称的__name__形参,甚至还有返回其全名的__qualname__形参,包括它属于哪个类(参见限定名称)。

这是一个经得起考验的方法。

将@CamHart和@Yuval的建议与@RoshOxymoron接受的答案结合起来,可以避免:

_hidden和潜在弃用的方法 在堆栈中建立索引(可以在未来的python中重新排序)

所以我认为这对未来的python版本(在2.7.3和3.3.2测试)很有帮助:

from __future__ import print_function
import inspect

def bar():
    print("my name is '{}'".format(inspect.currentframe().f_code.co_name))

更新:在3.7.10,3.8.10和3.9.5测试

我最近尝试使用上面的答案从该函数的上下文中访问函数的文档字符串,但由于上面的问题只返回名称字符串,因此不起作用。

幸运的是,我找到了一个简单的解决办法。如果像我一样,想要引用函数,而不是简单地获取表示名称的字符串,那么可以对函数名称的字符串应用eval()。

import sys
def foo():
    """foo docstring"""
    print(eval(sys._getframe().f_code.co_name).__doc__)

从上面所有使用inspect库的答案来看,所有的都是这样写的:

import inspect

inspect.stack()[0][3]

但是,由于inspect.stack()的返回,[0]是一个NamedTuple,其形式为:

FrameInfo(frame=<frame at 0x103578810, file '<stdin>', line 1, code <module>>, filename='<stdin>', lineno=1, function='<module>', code_context=None, index=None)

可以简单地通过名称调用,即inspect.stack()[0].function

这里可以看到一个小的虚拟例子:

    def test_train_UGRIZY_noZ(self, architecture, dataset, hyperrun, wloss):
        log.warning(f"{inspect.stack()[0].function} -- Not Implemented Yet")
        pass

当运行时打印:

WARNING - test_train_UGRIZY_noZ -- Not Implemented Yet