在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?
当前回答
.f_back.f_code Sincesys._getframe()。Co_name在python 3.9中根本不起作用,下面可以从现在开始使用:
from inspect import currentframe
def testNameFunction() -> str:
return currentframe().f_back.f_code.co_name
print(f'function name is {testNameFunction()}(...)')
结果:
function name is testNameFunction(...)
其他回答
这实际上是由这个问题的其他答案推导出来的。
以下是我的看法:
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()的文章和计时]。
这是一个经得起考验的方法。
将@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测试
我不知道为什么人们会把它弄得这么复杂:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
我建议不要依赖于堆栈元素。如果有人在不同的上下文中使用你的代码(例如python解释器),你的堆栈将改变并破坏你的索引([0][3])。
我建议你这样做:
class MyClass:
def __init__(self):
self.function_name = None
def _Handler(self, **kwargs):
print('Calling function {} with parameters {}'.format(self.function_name, kwargs))
self.function_name = None
def __getattr__(self, attr):
self.function_name = attr
return self._Handler
mc = MyClass()
mc.test(FirstParam='my', SecondParam='test')
mc.foobar(OtherParam='foobar')
我用自己的方法在多重继承场景中安全地调用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__作为当前函数名。