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没有

在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')