Rob*_*Rob 423 python function introspection traceback
在Python中,不使用该traceback
模块,有没有办法从该函数中确定函数的名称?
假设我有一个带功能栏的模块foo.执行时foo.bar()
,有没有办法让酒吧知道酒吧的名字?或者更好的是,foo.bar
这个名字?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
Run Code Online (Sandbox Code Playgroud)
小智 372
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
Run Code Online (Sandbox Code Playgroud)
Ros*_*ron 176
Python没有在函数本身中访问函数或其名称的功能.它已被提议但被拒绝.如果你不想自己玩堆栈,你应该使用"bar"
或bar.__name__
取决于上下文.
给出的拒绝通知是:
该PEP被拒绝.目前尚不清楚它应该如何实现或边缘情况下的精确语义应该是什么,并且没有给出足够的重要用例.反应一直不冷不热.
Ale*_*sky 139
有几种方法可以获得相同的结果:
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)
Run Code Online (Sandbox Code Playgroud)
请注意,这些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
Run Code Online (Sandbox Code Playgroud)
bgp*_*ter 44
您可以使用@Andreas Jung显示的方法获取它所定义的名称,但这可能不是调用该函数的名称:
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
Run Code Online (Sandbox Code Playgroud)
这种区别对你来说是否重要我不能说.
Ron*_*vis 38
functionNameAsString = sys._getframe().f_code.co_name
Run Code Online (Sandbox Code Playgroud)
我想要一个非常类似的东西,因为我想将函数名称放在我的代码中的许多地方的日志字符串中.可能不是最好的方法,但这里有一种获取当前函数名称的方法.
xxy*_*zzy 21
我把这个方便的实用程序放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
Run Code Online (Sandbox Code Playgroud)
用法:
myself()
Run Code Online (Sandbox Code Playgroud)
Bjo*_*orn 20
我想这inspect
是最好的方法.例如:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
Run Code Online (Sandbox Code Playgroud)
cad*_*6uk 14
我发现了一个将编写函数名称的包装器
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()
Run Code Online (Sandbox Code Playgroud)
这将打印
my_funky_name
存根
Gin*_*ino 12
这实际上是从问题的其他答案中得出的.
这是我的看法:
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
Run Code Online (Sandbox Code Playgroud)
这个版本比使用inspect.stack()的可能优势在于它应该快几千倍[参见Alex Melihoff关于使用sys._getframe()和使用inspect.stack()的帖子和时间.
hob*_*obs 11
这是一种面向未来的方法.
将@ 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))
Run Code Online (Sandbox Code Playgroud)
Lee*_*Lee 10
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()
Run Code Online (Sandbox Code Playgroud)
在IDE中代码输出
你好,我是foo,爸爸是
你好,我是酒吧,爸爸是foo
你好,我是酒吧,爸爸是
小智 9
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())
Run Code Online (Sandbox Code Playgroud)
测试:
a = A()
a.test_class_func_name()
test_func_name()
Run Code Online (Sandbox Code Playgroud)
输出:
test_class_func_name
test_func_name
Run Code Online (Sandbox Code Playgroud)
你可以使用装饰器:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
Run Code Online (Sandbox Code Playgroud)
小智 6
我建议不要依赖堆栈元素。如果有人在不同的上下文中使用您的代码(例如 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')
Run Code Online (Sandbox Code Playgroud)
我不确定为什么人们会变得复杂:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
Run Code Online (Sandbox Code Playgroud)
使用__name__
属性:
# foo.py
def bar():
print(f"my name is {bar.__name__}")
Run Code Online (Sandbox Code Playgroud)
您可以使用__name__
属性轻松地从函数内部访问函数的名称。
>>> def bar():
... print(f"my name is {bar.__name__}")
...
>>> bar()
my name is bar
Run Code Online (Sandbox Code Playgroud)
我自己多次遇到过这个问题,正在寻找解决方法。正确答案包含在 Python 的文档中(请参阅可调用类型部分)。
每个函数都有一个__name__
返回其名称的__qualname__
参数,甚至返回其全名的参数,包括它属于哪个类(请参阅限定名称)。
我用我自己的方法在多继承场景中安全地调用 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
Run Code Online (Sandbox Code Playgroud)
示例用法:
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)()
Run Code Online (Sandbox Code Playgroud)
测试它:
a = C()
a.test()
Run Code Online (Sandbox Code Playgroud)
输出:
called from C
called from A
called from B
Run Code Online (Sandbox Code Playgroud)
在每个 @with_name 装饰方法中,您可以访问 self.__fname__ 作为当前函数名。
我做了CamHart所说的:
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
Run Code Online (Sandbox Code Playgroud)
输出:
C:\ Python \ Python36 \ python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere
流程结束,退出代码为0
我最近尝试使用上述答案从该函数的上下文访问函数的文档字符串,但由于上述问题仅返回名称字符串,因此它不起作用。
幸运的是,我找到了一个简单的解决方案。如果像我一样,您想引用函数而不是简单地获取代表名称的字符串,您可以将 eval() 应用于函数名称的字符串。
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
Run Code Online (Sandbox Code Playgroud)
小智 5
这很容易用装饰器来完成。
>>> 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')
Run Code Online (Sandbox Code Playgroud)