在Python中,如果不使用traceback模块,是否有一种方法可以从函数内部确定函数的名称?

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

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

当前回答

.f_back.f_code Sincesys._getframe()。Co_name在python 3.9中根本不起作用,下面可以从现在开始使用:

from inspect import currentframe


def testNameFunction() -> str:
    return currentframe().f_back.f_code.co_name


print(f'function name is {testNameFunction()}(...)')

结果:

function name is testNameFunction(...)

其他回答

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

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

我用自己的方法在多重继承场景中安全地调用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__作为当前函数名。

使用__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__形参,包括它属于哪个类(参见限定名称)。

我不知道为什么人们会把它弄得这么复杂:

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