在Python中,不使用traceback
模块,有没有一种方法可以确定一个函数在函数内部的名称?
假设我有一个名为foo
的模块和一个名为bar
的函数。当执行foo.bar()
时,是否有一种方法让bar
知道自己的名称?或者更好的是,知道foo.bar
的名称?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
在Python中,不使用traceback
模块,有没有一种方法可以确定一个函数在函数内部的名称?
假设我有一个名为foo
的模块和一个名为bar
的函数。当执行foo.bar()
时,是否有一种方法让bar
知道自己的名称?或者更好的是,知道foo.bar
的名称?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
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
foo()
输出:
foo
<module_caller_of_foo>
print(inspect.currentframe().f_code.co_name)
,或者用以下代码获取调用者的名称:print(inspect.currentframe().f_back.f_code.co_name)
。我认为这样会更快,因为它不需要像inspect.stack()
一样检索整个堆栈帧列表。 - Michaelinspect.currentframe().f_back.f_code.co_name
无效,而inspect.stack()[0][3]
可行。 - Dustin Wyatt3
是什么意思? - tommy.carstensenPython没有一种方法可以在函数本身内部访问函数或其名称。虽然已经有提案(PEP 3130),但被拒绝了。如果你不想自己修改堆栈,你应该根据上下文使用"bar"
或bar.__name__
。
关于该提案的拒绝通知如下:
该PEP被拒绝。目前尚不清楚它应该如何实现,以及在边缘情况下应该具有什么精确语义,而且重要的用例不够多。反应最多只是温热的。
inspect.currentframe()
是其中一种方法。 - Yuvalprint(inspect.currentframe().f_code.co_name)
。 - hobs有几种方法可以获得相同的结果:
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
更新于2021年08月(原始帖子是针对Python2.7编写的)
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
500 loops, best of 5: 390 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
500 loops, best of 5: 398 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
2000000 loops, best of 5: 176 nsec per loop
python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
5000000 loops, best of 5: 62.8 nsec per loop
inspect.currentframe()
看起来是执行时间和使用私有成员之间的一个很好的权衡。 - FabienAndresys._getframe().f_code.co_name
而非 inspect.currentframe().f_code.co_name
,仅因为我已经导入了 sys
模块。考虑到速度看起来相当接近,这是一个合理的决定吗? - PatrickTsys._getframe().f_back.f_code.co_name
来获取调用者的名称。 - Fernando CrespofunctionNameAsString = sys._getframe().f_code.co_name
我想要一个非常相似的东西,因为我想将函数名放入一个在我的代码中出现多次的日志字符串中。这可能不是最好的方法,但这是获取当前函数名称的一种方式。
_
表示私有方法。请不要公开调用它们。您可能想使用inspect.currentframe()
,它是一个公共方法。 - Roland_
表示一个私有方法。请不要公开调用它们。你可能想要使用 inspect.currentframe()
,这是一个公共方法。 - undefinedinspect
,正如一个名叫gardah的评论(在上面的一个回答中)所说,它需要很长时间。如果问题是因为它是私有的,那么就需要说服开发人员提供一个名为 getCurrentFunctionName()
和 getParentFunctionName()
的公共函数。 - Nav您可以使用@Andreas Jung所示的方法获取函数定义时的名称,但这可能不是调用函数时使用的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
无法确定该区分对您是否重要。.func_name
一样的情况。值得记住,在Python中,类名和函数名是一回事,而引用它们的变量是另一回事。 - KosFoo2()
打印 Foo
。例如:Foo2 = function_dict['Foo']; Foo2()
。在这种情况下,Foo2 是一个函数指针,用于命令行解析器。 - Harvey我将这个方便的工具放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
使用:
myself()
lambda
...)创建命名函数。请使用def
正常定义函数,避免可能出现的多种问题。 - pabouk - Ukraine stay strong我猜 inspect
是最好的方法来实现这个目标。例如:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
inspect.stack()[0].function
代替inspect.stack()[0][3]
,即使堆栈追踪中的语义发生变化,该方法应该更加健壮。 - Tom Pohl这实际上是从其他回答问题的答案中得出的。
以下是我的看法:
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
使用sys._getframe()相比使用inspect.stack()的明显优势在于它应该快上数千倍 [详见Alex Melihoff关于使用sys._getframe()与使用inspect.stack()时序的帖子]。
我发现了一个包装器,它可以写入函数名称
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()
这将打印
我的花里胡哨的名字
STUB
my_funky_name
函数内部执行此操作的方式是 my_funky_name.__name__
。您可以将 func.__name__
作为新参数传递到该函数中。func(*args, **kwargs, my_name=func.__name__)
。要从函数内部获取装饰器的名称,我认为需要使用 inspect
。但从运行函数控制我的函数的名称,听起来就像是一个美丽的梗的开端 :) - cad106uk我不确定为什么人们会把它弄得很复杂:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))