在Python中,如果不使用traceback模块,是否有一种方法可以从函数内部确定函数的名称?
假设我有一个模块foo和一个功能栏。当执行foo.bar()时,是否有一种方法让bar知道bar的名字?或者更好的是,foo。酒吧的名字吗?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
在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
def func_name():
"""
:return: name of caller
"""
return sys._getframe(1).f_code.co_name
class A(object):
def __init__(self):
pass
def test_class_func_name(self):
print(func_name())
def test_func_name():
print(func_name())
测试:
a = A()
a.test_class_func_name()
test_func_name()
输出:
test_class_func_name
test_func_name
其他回答
functionNameAsString = sys._getframe().f_code.co_name
我想要一个非常相似的东西,因为我想把函数名放在一个log字符串中,在我的代码中有很多地方。可能不是最好的方法,但这里有一种获取当前函数名称的方法。
这实际上是由这个问题的其他答案推导出来的。
以下是我的看法:
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()的文章和计时]。
我用自己的方法在多重继承场景中安全地调用super(我把所有代码都放在这里)
def safe_super(_class, _inst):
"""safe super call"""
try:
return getattr(super(_class, _inst), _inst.__fname__)
except:
return (lambda *x,**kx: None)
def with_name(function):
def wrap(self, *args, **kwargs):
self.__fname__ = function.__name__
return function(self, *args, **kwargs)
return wrap
示例用法:
class A(object):
def __init__():
super(A, self).__init__()
@with_name
def test(self):
print 'called from A\n'
safe_super(A, self)()
class B(object):
def __init__():
super(B, self).__init__()
@with_name
def test(self):
print 'called from B\n'
safe_super(B, self)()
class C(A, B):
def __init__():
super(C, self).__init__()
@with_name
def test(self):
print 'called from C\n'
safe_super(C, self)()
测试:
a = C()
a.test()
输出:
called from C
called from A
called from B
在每个@with_name修饰的方法中,您可以访问self。__fname__作为当前函数名。
我把这个实用工具放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
用法:
myself()
从上面所有使用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