如何在Python中实现与C语言的__FUNCTION__相同的功能?

5 投票
5 回答
2699 浏览
提问于 2025-04-16 02:26

在C语言中,我可以在一个函数里放一个日志打印,比如这样:

void xx_lock (int xx_flag)
{
  printf ("%s: START with %d\n", __FUNCTION__, xx_flag);
}

这样我就可以在任何需要的地方复制同样的代码行,它会在日志中显示出函数的名字。我想在Python中做类似的事情。但是如果我用

__name__

同样的方式,它显示的是模块的名字,而不是函数的名字。

def xxx_lock(xx_flag=0)
    sys.stdout.write("%s: START with %d\n" % (__name__, xx_flag))

有没有什么简单的方法可以让我在这个例子中显示Python函数的名字?希望能输出像这样:

xxx_lock: START with 1

编辑:我在例子中添加了参数。

5 个回答

2
import inspect
inspect.getframeinfo(inspect.currentframe()).function

这个方法提供的功能最像C语言中的__FUNCTION__,不过正如katrielalex所说,这其实是一种变通的做法。最终,使用装饰器会是更好的解决方案。

9

你问的这个问题其实是没法做到的(好好地做到是没办法的——有些方法可以实现,但都是些很糟糕的技巧)。不过,你其实不想这样做。换个角度想:你想要一个简单的方法来修改一个函数,让它在开始时记录日志。直接改这个函数的源代码并不是个好办法——毕竟,记录日志和这个函数的实际工作没什么关系!相反,你应该在函数执行后再进行修改。

def startLog( func ):
    def loggedFunc( *args, **kwargs ):
        print( "starting {0} with {1}".format( func.__name__, args[ 0 ] ) )
        return func( *args, **kwargs )
    
    return loggedFunc

@startLog
def theFunc( ):
    print( "running theFunc" )

theFunc( )
# starting theFunc
# running theFunc

这里有个Python的装饰器示例:它在定义时把一个函数转换成另一个函数。这其实是更简洁的写法,等于:

def theFunc( ):
    print( "running theFunc" )
theFunc = startLog( theFunc )

换句话说,你是在直接操作这个函数对象(记住——函数也是对象,你可以传递它们、修改它们、查看它们的属性等等!),然后重新定义它。看源代码,我们可以看到startLog定义了一个新函数(loggedFunc),这个新函数首先打印一条日志,然后再运行原来的函数,并把参数传递给它。使用这个装饰器后,theFunc就被替换成了loggedFunc,所以现在绑定到theFunc这个名字的函数会自己记录日志了!

这样说清楚了吗?如果需要,我可以更详细地解释。

补充

正如之前提到的,这个回答并没有直接解决你的问题;如果你需要更多功能,可以使用logging模块,它能满足你所有的需求,甚至更多。遍历调用栈的做法既麻烦又不稳定,真的不推荐哦 =p。

8

katrielalex说得对,你不应该尝试用“C语言”的方式来做这件事。Python自带了很多功能,那为什么不直接使用这些功能呢?

import logging, sys

logging.basicConfig(format="%(filename)s:%(funcName)s:%(message)s",level=logging.DEBUG,stream=sys.stderr)

def testFunc():
    logging.debug("entering")

testFunc()

撰写回答