首页 文章

从该函数中确定函数名称(不使用回溯)

提问于
浏览
330

在Python中,不使用 traceback 模块,有没有办法从该函数中确定函数的名称?

假设我有一个带功能栏的模块foo . 执行 foo.bar() 时,有没有办法让酒吧知道酒吧的名字?或者更好, foo.bar 的名字?

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?

18 回答

  • 6
    import inspect
    
    def foo():
       print(inspect.stack()[0][3])
    
  • 40

    Python没有在函数本身中访问函数或其名称的功能 . 它一直是proposed但被拒绝了 . 如果您不想自己使用堆栈,则应根据上下文使用 "bar"bar.__name__ .

    给出的拒绝通知是:

    此PEP被拒绝 . 目前尚不清楚它应该如何实现或边缘情况下的精确语义应该是什么,并且没有足够的重要用例给出 . 反应一直不冷不热 .

  • 2

    有几种方法可以获得相同的结果:

    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
    
  • 11

    您可以使用the approach that @Andreas Jung shows获取使用the approach that @Andreas Jung shows定义的名称,但这可能不是调用该函数的名称:

    import inspect
    
    def Foo():
       print inspect.stack()[0][3]
    
    Foo2 = Foo
    
    >>> Foo()
    Foo
    
    >>> Foo2()
    Foo
    

    这种区别对你来说是否重要我不能说 .

  • 6
    functionNameAsString = sys._getframe().f_code.co_name
    

    我想要一个非常相似的东西,因为我想将函数名称放在我的代码中的许多地方的日志字符串中 . 可能不是最好的方法,但这里有一种获取当前函数名称的方法 .

  • 114

    我把这个方便的实用程序放在附近:

    import inspect
    myself = lambda: inspect.stack()[1][3]
    

    用法:

    myself()
    
  • 20

    我找到了一个可以编写函数名的包装器

    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 STUB

  • 139

    print(inspect.stack()[0].function) 似乎也有用(Python 3.5) .

  • 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()的帖子和时间 .

  • 301
    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
    
  • 10

    我想 inspect 是最好的方法 . 例如:

    import inspect
    def bar():
        print("My name is", inspect.stack()[0][3])
    
  • 2

    这是一种面向未来的方法 .

    将@CamHart 's and @Yuval'的建议与@ RoshOxymoron的accepted answer结合使用可以避免:

    • _hidden 以及可能已弃用的方法

    • 索引到堆栈中(可以在将来的pythons中重新排序)

    所以我认为这对未来的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))
    
  • 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'
    
  • 9

    我做了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结束

  • 32

    我做自己的方法用于在多重继承场景中调用超级安全(我把所有的代码)

    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__作为当前函数名称 .

  • 9

    使用此(基于#Ron Davis的回答):

    import sys
    
    def thisFunctionName():
        """Returns a string with the name of the function it's called from"""
        return sys._getframe(1).f_code.co_name
    
  • 4

    我最近尝试使用上面的答案从该函数的上下文访问函数的docstring,但由于上面的问题只返回名称字符串,它不起作用 .

    幸运的是,我找到了一个简单的解如果像我一样,你想引用函数而不是简单地获取表示名称的字符串,你可以将eval()应用于函数名的字符串 .

    import sys
    def foo():
        """foo docstring"""
        print(eval(sys._getframe().f_code.co_name).__doc__)
    

相关问题