Answers:
Python没有功能来访问函数本身或函数内部的名称。已经提出但遭到拒绝。如果您不想自己玩堆栈,则应该使用"bar"
或bar.__name__
取决于上下文。
给定的拒绝通知是:
该PEP被拒绝。目前尚不清楚在极端情况下应该如何实现它或确切的语义,也没有足够的重要用例。回应充其量是冷淡的。
inspect.currentframe()
就是这样一种方式。
print(inspect.currentframe().f_code.co_name)
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
[1][3]
可以获取呼叫者的姓名。
print(inspect.currentframe().f_code.co_name)
或获取呼叫者的姓名:print(inspect.currentframe().f_back.f_code.co_name)
。我认为应该更快,因为您不会像这样检索所有堆栈帧的列表inspect.stack()
。
inspect.currentframe().f_back.f_code.co_name
不适用于修饰的方法,而适用于inspect.stack()[0][3]
…
有几种方法可以得到相同的结果:
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
inspect.currentframe()
在执行时间和使用私人成员之间似乎是一个很好的权衡
0.100 usec
还是0.199 usec
比选项1和2快数百倍,可与选项4相提并论(尽管Antony Hatchkins发现选项3比选项4快三倍)。
sys._getframe().f_code.co_name
用完inspect.currentframe().f_code.co_name
只是因为我已经导入了sys
模块。这是一个合理的决定吗?(考虑到速度看起来非常相似)
您可以使用@Andreas Jung显示的方法来获得定义的名称,但这可能不是使用该函数调用的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
我不能说这种区别对您是否重要。
.func_name
。值得记住的是,Python中的类名和函数名是一回事,而引用它们的变量是另一回事。
Foo2()
打印Foo
。例如:Foo2 = function_dict['Foo']; Foo2()
。在这种情况下,Foo2是可能用于命令行解析器的函数指针。
functionNameAsString = sys._getframe().f_code.co_name
我想要一个非常类似的东西,因为我想将函数名称放在一个日志字符串中,该字符串在我的代码中占据了很多位置。可能不是执行此操作的最佳方法,但是这是一种获取当前函数名称的方法。
f
框架和co
代码。如果我将其保存在一些代码段中,我不会用得那么好:-)
我将这个方便的实用程序放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
用法:
myself()
我找到了一个将写函数名称的包装器
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
存根
my_funky_name.__name__
。您可以将func .__ name__作为新参数传递给函数。func(* args,** kwargs,my_name = func .__ name__)。为了从函数内部获取装饰器名称,我认为这需要使用inspect。但是在运行的函数中获得控制我的函数的函数的名称……好吧,听起来像是一个美丽的模因的开始:)
这实际上是从该问题的其他答案中得出的。
这是我的看法:
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版本(在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))
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
我不确定为什么人们会变得复杂:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
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
你好,我在酒吧,爸爸是
您可以使用装饰器:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
__name__
函数的属性。用法需要知道您要获取的东西,这在我没有动态定义函数的简单情况下对我来说似乎不太有用。
我使用自己的方法在多重继承场景中安全地调用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__作为当前函数名称。
我建议不要依赖堆栈元素。如果有人在不同的上下文(例如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')
用装饰器很容易做到这一点。
>>> from functools import wraps
>>> def named(func):
... @wraps(func)
... def _(*args, **kwargs):
... return func(func.__name__, *args, **kwargs)
... return _
...
>>> @named
... def my_func(name, something_else):
... return name, something_else
...
>>> my_func('hello, world')
('my_func', 'hello, world')
traceback
。甚至没有答案和评论的时代似乎也支持它。