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

时间:2021-10-19 16:00:08

In Python, without using the traceback module, is there a way to determine a function's name from within that function?

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

Say I have a module foo with a function bar. When executing foo.bar(), is there a way for bar to know bar's name? Or better yet, foo.bar's name?

假设我有一个函数栏的foo模块。在执行foo.bar()时,是否有方法让bar知道bar的名称?或者更好的是,foo。酒吧的名字吗?

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

16 个解决方案

#1


116  

Python doesn't have a feature to access the function or its name within the function itself. It has been proposed but rejected. If you don't want to play with the stack yourself, you should either use "bar" or bar.__name__ depending on context.

Python没有在函数本身中访问函数或其名称的功能。这一提议已被提出,但遭到拒绝。如果您不想自己玩堆栈,您应该使用“bar”或bar。__name__取决于上下文。

The given rejection notice is:

被给予的拒绝通知为:

This PEP is rejected. It is not clear how it should be implemented or what the precise semantics should be in edge cases, and there aren't enough important use cases given. response has been lukewarm at best.

这个PEP是拒绝。现在还不清楚应该如何实现它,或者在边界情况下应该使用什么精确的语义,并且没有足够的重要用例。人们的反应充其量也就是不温不火。

#2


261  

import inspect

def foo():
   print inspect.stack()[0][3]

#3


103  

There are a few ways to get the same result:

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

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)

Note that the inspect.stack calls are thousands of times slower than the alternatives:

注意检查。堆栈调用比其他方法慢数千倍:

$ 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

#4


37  

You can get the name that it was defined with using the approach that @Andreas Jung shows, but that may not be the name that the function was called with:

您可以使用@Andreas Jung显示的方法获得它所定义的名称,但这可能不是函数的名称:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

Whether that distinction is important to you or not I can't say.

这个区别对你是否重要我不能说。

#5


27  

functionNameAsString = sys._getframe().f_code.co_name

I wanted a very similar thing because I wanted to put the function name in a log string that went in a number of places in my code. Probably not the best way to do that, but here's a way to get the name of the current function.

我想要一个非常相似的东西,因为我想把函数名放在一个日志字符串中,这个日志字符串在我的代码中有很多位置。这可能不是最好的方法,但是有一种方法可以获得当前函数的名称。

#6


14  

I keep this handy utility nearby:

我把这个有用的工具放在附近:

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

Usage:

用法:

myself()

#7


12  

I found a wrapper that will write the function name

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

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()

This will print

这将打印

my_funky_name

my_funky_name

STUB

存根

#8


9  

This is actually derived from the other answers to the question.

这实际上是从这个问题的其他答案中推导出来的。

Here's my take:

这里是我采用的方法:

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

The likely advantage of this version over using inspect.stack() is that it should be thousands of times faster [see Alex Melihoff's post and timings regarding using sys._getframe() versus using inspect.stack() ].

与使用inspection .stack()相比,这个版本可能的优点是它应该快几千倍(参见Alex Melihoff关于使用system ._getframe()和使用inspection .stack()的文章和时间)。

#9


9  

print(inspect.stack()[0].function) seems to work too (Python 3.5).

print(inspection .stack()[0].function)似乎也可以工作(Python 3.5)。

#10


8  

I guess inspect is the best way to do this. Example:

我想检查是最好的方法。例子:

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

#11


8  

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())

Test:

测试:

a = A()
a.test_class_func_name()
test_func_name()

Output:

输出:

test_class_func_name
test_func_name

#12


7  

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()

In IDE the code outputs

在IDE中,代码输出

hello, I'm foo, daddy is

你好,我是foo,爸爸是

hello, I'm bar, daddy is foo

你好,我是bar,爸爸是foo

hello, I'm bar, daddy is

你好,我是bar,爸爸。

#13


5  

Here's a future-proof approach.

这是一个不会过时的方法。

Combining @CamHart's and @Yuval's suggestions with @RoshOxymoron's accepted answer has the benefit of avoiding:

结合@CamHart和@Yuval的建议和@RoshOxymoron的公认答案,可以避免:

  • _hidden and potentially deprecated methods
  • _hidden和潜在废弃的方法
  • indexing into the stack (which could be reordered in future pythons)
  • 对堆栈的索引(在以后的python中可以重新排序)

So I think this plays nice with future python versions (tested on 2.7.3 and 3.3.2):

因此,我认为这对于未来的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))

#14


4  

I did what CamHart said:

我照CamHart说的做了:

import sys
def myFunctionsHere():
    print(sys._getframe().f_code.co_name)

myFunctionsHere()

Output:

输出:

C:\Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere

Python C:\ \ Python36 \ Python。exe C:/ Python / GetFunctionsNames / TestFunctionsNames。py myFunctionsHere

Process finished with exit code 0

进程完成与退出代码0

#15


4  

You can use a decorator:

您可以使用decorator:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'

#16


2  

I do my own approach used for calling super with safety inside multiple inheritance scenario (I put all the code)

我使用我自己的方法在多个继承场景中调用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

sample usage:

示例用法:

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)()

testing it :

测试:

a = C()
a.test()

output:

输出:

called from C
called from A
called from B

Inside each @with_name decorated method you have access to self.__fname__ as the current function name.

在每个@with_name修饰的方法中,您都可以访问self。__fname__作为当前函数名。

#1


116  

Python doesn't have a feature to access the function or its name within the function itself. It has been proposed but rejected. If you don't want to play with the stack yourself, you should either use "bar" or bar.__name__ depending on context.

Python没有在函数本身中访问函数或其名称的功能。这一提议已被提出,但遭到拒绝。如果您不想自己玩堆栈,您应该使用“bar”或bar。__name__取决于上下文。

The given rejection notice is:

被给予的拒绝通知为:

This PEP is rejected. It is not clear how it should be implemented or what the precise semantics should be in edge cases, and there aren't enough important use cases given. response has been lukewarm at best.

这个PEP是拒绝。现在还不清楚应该如何实现它,或者在边界情况下应该使用什么精确的语义,并且没有足够的重要用例。人们的反应充其量也就是不温不火。

#2


261  

import inspect

def foo():
   print inspect.stack()[0][3]

#3


103  

There are a few ways to get the same result:

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

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)

Note that the inspect.stack calls are thousands of times slower than the alternatives:

注意检查。堆栈调用比其他方法慢数千倍:

$ 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

#4


37  

You can get the name that it was defined with using the approach that @Andreas Jung shows, but that may not be the name that the function was called with:

您可以使用@Andreas Jung显示的方法获得它所定义的名称,但这可能不是函数的名称:

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

Whether that distinction is important to you or not I can't say.

这个区别对你是否重要我不能说。

#5


27  

functionNameAsString = sys._getframe().f_code.co_name

I wanted a very similar thing because I wanted to put the function name in a log string that went in a number of places in my code. Probably not the best way to do that, but here's a way to get the name of the current function.

我想要一个非常相似的东西,因为我想把函数名放在一个日志字符串中,这个日志字符串在我的代码中有很多位置。这可能不是最好的方法,但是有一种方法可以获得当前函数的名称。

#6


14  

I keep this handy utility nearby:

我把这个有用的工具放在附近:

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

Usage:

用法:

myself()

#7


12  

I found a wrapper that will write the function name

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

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()

This will print

这将打印

my_funky_name

my_funky_name

STUB

存根

#8


9  

This is actually derived from the other answers to the question.

这实际上是从这个问题的其他答案中推导出来的。

Here's my take:

这里是我采用的方法:

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

The likely advantage of this version over using inspect.stack() is that it should be thousands of times faster [see Alex Melihoff's post and timings regarding using sys._getframe() versus using inspect.stack() ].

与使用inspection .stack()相比,这个版本可能的优点是它应该快几千倍(参见Alex Melihoff关于使用system ._getframe()和使用inspection .stack()的文章和时间)。

#9


9  

print(inspect.stack()[0].function) seems to work too (Python 3.5).

print(inspection .stack()[0].function)似乎也可以工作(Python 3.5)。

#10


8  

I guess inspect is the best way to do this. Example:

我想检查是最好的方法。例子:

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

#11


8  

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())

Test:

测试:

a = A()
a.test_class_func_name()
test_func_name()

Output:

输出:

test_class_func_name
test_func_name

#12


7  

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()

In IDE the code outputs

在IDE中,代码输出

hello, I'm foo, daddy is

你好,我是foo,爸爸是

hello, I'm bar, daddy is foo

你好,我是bar,爸爸是foo

hello, I'm bar, daddy is

你好,我是bar,爸爸。

#13


5  

Here's a future-proof approach.

这是一个不会过时的方法。

Combining @CamHart's and @Yuval's suggestions with @RoshOxymoron's accepted answer has the benefit of avoiding:

结合@CamHart和@Yuval的建议和@RoshOxymoron的公认答案,可以避免:

  • _hidden and potentially deprecated methods
  • _hidden和潜在废弃的方法
  • indexing into the stack (which could be reordered in future pythons)
  • 对堆栈的索引(在以后的python中可以重新排序)

So I think this plays nice with future python versions (tested on 2.7.3 and 3.3.2):

因此,我认为这对于未来的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))

#14


4  

I did what CamHart said:

我照CamHart说的做了:

import sys
def myFunctionsHere():
    print(sys._getframe().f_code.co_name)

myFunctionsHere()

Output:

输出:

C:\Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere

Python C:\ \ Python36 \ Python。exe C:/ Python / GetFunctionsNames / TestFunctionsNames。py myFunctionsHere

Process finished with exit code 0

进程完成与退出代码0

#15


4  

You can use a decorator:

您可以使用decorator:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'

#16


2  

I do my own approach used for calling super with safety inside multiple inheritance scenario (I put all the code)

我使用我自己的方法在多个继承场景中调用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

sample usage:

示例用法:

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)()

testing it :

测试:

a = C()
a.test()

output:

输出:

called from C
called from A
called from B

Inside each @with_name decorated method you have access to self.__fname__ as the current function name.

在每个@with_name修饰的方法中,您都可以访问self。__fname__作为当前函数名。