在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 sys

# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name


def testFunction():
    print "You are in function:", currentFuncName()
    print "This function's caller was:", currentFuncName(1)    


def invokeTest():
    testFunction()


invokeTest()

# end of file

与使用inspect.stack()相比,这个版本可能的优势是它应该快数千倍[参见Alex Melihoff关于使用sys._getframe()与使用inspect.stack()的文章和计时]。

其他回答

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

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

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

我想检查是最好的方法。例如:

import inspect
def bar():
    print("My name is", inspect.stack()[0][3])

这实际上是由这个问题的其他答案推导出来的。

以下是我的看法:

import sys

# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name


def testFunction():
    print "You are in function:", currentFuncName()
    print "This function's caller was:", currentFuncName(1)    


def invokeTest():
    testFunction()


invokeTest()

# end of file

与使用inspect.stack()相比,这个版本可能的优势是它应该快数千倍[参见Alex Melihoff关于使用sys._getframe()与使用inspect.stack()的文章和计时]。

使用__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__形参,包括它属于哪个类(参见限定名称)。

你可以使用@Andreas Jung显示的方法获得它定义时的名称,但这可能不是调用函数时的名称:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

这种区别对你来说是否重要,我不能说。