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?
小智 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
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)
请注意,这些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
bgp*_*ter 44
您可以使用@Andreas Jung显示的方法获取它所定义的名称,但这可能不是调用该函数的名称:
import inspect
def Foo():
   print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
这种区别对你来说是否重要我不能说.
Ron*_*vis 38
functionNameAsString = sys._getframe().f_code.co_name
我想要一个非常类似的东西,因为我想将函数名称放在我的代码中的许多地方的日志字符串中.可能不是最好的方法,但这里有一种获取当前函数名称的方法.
xxy*_*zzy 21
我把这个方便的实用程序放在附近:
import inspect
myself = lambda: inspect.stack()[1][3]
用法:
myself()
Bjo*_*orn 20
我想这inspect是最好的方法.例如:
import inspect
def bar():
    print("My name is", inspect.stack()[0][3])
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()
这将打印
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
这个版本比使用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))
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()
在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())
测试:
a = A()
a.test_class_func_name()
test_func_name()
输出:
test_class_func_name
test_func_name
你可以使用装饰器:
def my_function(name=None):
    return name
def get_function_name(function):
    return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
小智 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')
我不确定为什么人们会变得复杂:
import sys 
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
使用__name__属性:
# foo.py
def bar():
    print(f"my name is {bar.__name__}")
您可以使用__name__属性轻松地从函数内部访问函数的名称。
>>> def bar():
...     print(f"my name is {bar.__name__}")
...
>>> bar()
my name is bar
我自己多次遇到过这个问题,正在寻找解决方法。正确答案包含在 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
示例用法:
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__ 作为当前函数名。
我做了CamHart所说的:
import sys
def myFunctionsHere():
    print(sys._getframe().f_code.co_name)
myFunctionsHere()
输出:
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__)
小智 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')