Python 从该函数中确定函数名(不使用回溯)
在Python中,如果不使用Python 从该函数中确定函数名(不使用回溯),python,function,introspection,traceback,Python,Function,Introspection,Traceback,在Python中,如果不使用回溯模块,是否有办法从函数中确定函数名 假设我有一个带有功能条的模块foo。执行foo.bar()时,是否有办法让bar知道bar的名称?或者更好的是,foo.bar的名字 #foo.py def bar(): print "my name is", __myname__ # <== how do I calculate this at runtime? #foo.py def bar(): 打印“我的名字是”,Python没有
回溯
模块,是否有办法从函数中确定函数名
假设我有一个带有功能条的模块foo
。执行foo.bar()
时,是否有办法让bar
知道bar
的名称?或者更好的是,foo.bar
的名字
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
#foo.py
def bar():
打印“我的名字是”,Python没有访问函数或函数本身中函数名的功能。它被拒绝了。如果您不想自己使用堆栈,则应根据上下文使用“bar”
或bar.\uuuu name\uuuu
给出的拒收通知为:
该政治公众人物被拒绝。目前还不清楚应该如何实现它,或者在边缘案例中应该有什么精确的语义,并且没有给出足够的重要用例。反应充其量也很冷淡
我想inspect
是最好的方法。例如:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
您可以使用来获取定义该函数的名称,但该名称可能不是调用该函数时使用的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
我不能说这种区别对你是否重要
functionNameAsString = sys._getframe().f_code.co_name
我想要一个非常类似的东西,因为我想把函数名放在一个日志字符串中,这个字符串在我的代码中有很多地方。可能不是最好的方法,但这里有一种获取当前函数名称的方法。有几种方法可以获得相同的结果:
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
我找到了一个将写入函数名的包装器
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()
这会打印出来
我的时髦名字
存根
我把这个方便的工具放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
用法:
myself()
这是一种经得起未来考验的方法
将@CamHart和@Yuval的建议与@RoshOxymoron的建议相结合,有助于避免:
\u隐藏的
和可能不推荐的方法
- 索引到堆栈中(可以在将来的python中重新排序)
因此,我认为这在未来的python版本(在2.7.3和3.3.2上测试)中表现良好:
您可以使用装饰器:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
这实际上是从问题的其他答案中得出的
以下是我的看法:
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.\u getframe()与使用inspect.stack()的文章和计时]
在IDE中,代码输出
你好,我是福,爸爸是
你好,我是巴,爸爸是福
你好,我是酒吧,爸爸是
我使用自己的方法在多重继承场景中使用安全性调用super(我将所有代码放在一起)
示例用法:
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。u fname_uu作为当前函数名。print(inspect.stack()[0].function)
似乎也可以使用(Python 3.5)
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
测试:
输出:
test_class_func_name
test_func_name
我最近尝试使用上面的答案从函数的上下文访问函数的docstring,但是由于上面的问题只返回名称字符串,所以它不起作用
幸运的是,我找到了一个简单的解决办法。如果像我一样,您希望引用函数,而不是简单地获取表示名称的字符串,您可以将eval()应用于函数名的字符串
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
我建议不要依赖堆栈元素。如果有人在不同的上下文中使用您的代码(例如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')
我不知道为什么人们会把它复杂化:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
这是很容易做到的装饰
>>> 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')
使用\uuuu名称\uuuuu
属性:
#foo.py
def bar():
打印(f“我的名字是{bar.{u name}”)
您可以使用属性从函数中轻松访问函数名
>>定义栏():
... 打印(f“我的名字是{bar.{u name}”)
...
>>>bar()
我叫巴
我自己也曾多次遇到过这个问题,正在寻找解决方法。正确答案包含在Python文档中(请参见第节)
每个函数都有一个返回其名称的\uuuuuu name\uuuuuu
参数,甚至还有一个返回其全名的\uuuuuuuu qualname\uuuuu
参数,包括它所属的类(请参见)。这很好,因为您还可以执行[1][3]
来获取调用方的名称。您还可以使用:打印(inspect.currentframe().f_code.co_name)
或获取调用方名称:打印(检查.currentframe().f_back.f_code.co_name)
。我认为它应该会更快,因为您没有像inspect.stack()
那样检索所有堆栈帧的列表。inspect.currentframe().f_back.f_code.co_name
不使用修饰的方法,而inspect.stack()[0][3]
可以……请注意:inspect.stack()可能会导致沉重的性能开销,因此请节约使用!在我的手臂上,由于某种原因,花了240毫秒才完成。@Michael请将您的评论作为答案发布。情况与.func\u name
相同。值得记住的是,Python中的类名和函数名是一回事,引用它们的变量是另一回事。有时您可能希望Foo2()
打印Foo
。例如:Foo2=function_dict['Foo'];Foo2()
。在本例中,Foo2可能是一个命令行解析器的函数指针。这有什么样的速度含义?关于什么的速度含义?是否存在需要在硬实时情况下或其他情况下获取此信息的情况?inspect.currentframe()
就是这样一种方法。将@CamHart的方法与@Yuval的方法相结合可以避免“隐藏”和潜在的错误
test_class_func_name
test_func_name
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
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')
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
>>> 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')