在Python中,不使用traceback
模块,是否可以从该函数中确定函数名称?
说我有一个带功能栏的模块foo。 当执行foo.bar()
,bar是否有办法知道bar的名称? 或者更好的是foo.bar
的名称?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
#1楼
functionNameAsString = sys._getframe().f_code.co_name
我想要一个非常类似的东西,因为我想将函数名称放在一个日志字符串中,该字符串在我的代码中占据了很多位置。 可能不是这样做的最佳方法,但是这是一种获取当前函数名称的方法。
#2楼
有几种方法可以得到相同的结果:
from __future__ import print_function
import sys
import inspect
def what_is_my_name():
print(inspect.stack()[0][0].f_code.co_name)
print(inspect.stack()[0][3])
print(inspect.currentframe().f_code.co_name)
print(sys._getframe().f_code.co_name)
请注意, inspect.stack
调用比其他方法慢数千倍:
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop
#3楼
我找到了一个将写函数名称的包装器
from functools import wraps
def tmp_wrap(func):
@wraps(func)
def tmp(*args, **kwargs):
print func.__name__
return func(*args, **kwargs)
return tmp
@tmp_wrap
def my_funky_name():
print "STUB"
my_funky_name()
这将打印
my_funky_name
存根
#4楼
我将这个方便的实用程序放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
用法:
myself()
#5楼
这是一种面向未来的方法。
将@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))
#6楼
您可以使用装饰器:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
#7楼
这实际上是从问题的其他答案中得出的。
这是我的看法:
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()的时序]。
#8楼
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,爸爸是
你好,我是酒吧,爸爸是foo
你好,我在酒吧,爸爸是
#9楼
我使用自己的方法在多重继承场景中安全地调用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__作为当前函数名称。
#10楼
print(inspect.stack()[0].function)
似乎也可以工作(Python 3.5)。
#11楼
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
#12楼
我做了CamHart所说的:
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
输出:
C:\\ Python \\ Python36 \\ python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere
流程结束,退出代码为0
#13楼
import inspect
def foo():
print(inspect.stack()[0][3])
print(inspect.stack()[1][3]) #will give the caller of foos name, if something called foo
#14楼
Python没有功能来访问函数或函数本身中的名称。 已经提出但遭到拒绝。 如果您不想自己玩堆栈,则应根据上下文使用"bar"
或bar.__name__
。
给定的拒绝通知是:
该PEP被拒绝。 尚不清楚在极端情况下应如何实现它或精确的语义,并且给出的重要用例还不够多。 回应充其量是冷淡的。
#15楼
我想inspect
是最好的方法。 例如:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
#16楼
您可以使用@Andreas Jung显示的方法来获得定义的名称,但这可能不是使用该函数调用的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
我不能说这种区别对您是否重要。
#17楼
使用此方法(基于#Ron Davis的答案):
import sys
def thisFunctionName():
"""Returns a string with the name of the function it's called from"""
return sys._getframe(1).f_code.co_name
#18楼
我最近尝试使用以上答案从该函数的上下文访问该函数的文档字符串,但是由于上述问题仅返回了名称字符串,因此它不起作用。
幸运的是,我找到了一个简单的解决方案。 如果像我一样,您想引用该函数,而不是简单地获取表示名称的字符串,您可以将eval()应用于函数名称的字符串。
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
#19楼
我建议不要依赖堆栈元素。 如果有人在不同的上下文(例如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')
#20楼
我不确定为什么人们会变得复杂:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))