在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?
当前回答
str(str(inspect.currentframe())).split(' ')[-1][:-1]
其他回答
你可以使用@Andreas Jung显示的方法获得它定义时的名称,但这可能不是调用函数时的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
这种区别对你来说是否重要,我不能说。
从上面所有使用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
我想检查是最好的方法。例如:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
我喜欢使用装饰器的想法,但我更喜欢避免触及函数参数。因此,我提供了另一种选择:
import functools
def withname(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
global __name
__saved_name = globals().get("__name")
__name = f.__name__
ret = f(*args, **kwargs)
__name = __saved_name
return ret
return wrapper
@withname
def f():
print(f"in f: __name=={__name}")
g()
print(f"back in f: __name=={__name}")
@withname
def g():
print(f"in g: __name=={__name}")
由于__name是一个全局变量,所以在调用函数时需要保存和恢复__name。调用上面的f()会产生:
in f: __name==f
in g: __name==g
back in f: __name==f
不幸的是,如果我们不改变函数参数,就没有全局变量的替代品。引用一个不是在函数上下文中创建的变量,将生成寻找全局变量的代码:
>>> def f(): print(__function__)
>>> from dis import dis
>>> dis(f)
1 0 LOAD_GLOBAL 0 (print)
2 LOAD_GLOBAL 1 (__function__)
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
你可以使用装饰器:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'