关于函数:在python中print时包含当前方法名

Including the current method name when printing in Python

在C程序(和使用GCC)中,我经常会创建一个包含当前函数名的调试打印宏。也就是说,类似于:

1
#define DPRINTF(fmt, ...) printf("[%s]" fmt, __FUNCTION__, ##__VA_ARGS__)

使用时,当前函数将在每次打印前准备好,在运行时提供更有用的调试信息。例如,以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

#define DPRINT(fmt, ...) printf("[%s]" fmt, __FUNCTION__, ##__VA_ARGS__)

void testfunction1(){
    DPRINT("Running %d
"
,1);
}

void testfunction2(){
    DPRINT("Running %d
"
,2);
}

int main(void) {
    DPRINT("Running: %d
"
,0);
    testfunction1();
    testfunction2();
    return 0;
}

输出:

1
2
3
[main] Running: 0
[testfunction1] Running 1
[testfunction2] Running 2

像这样的事情可以在Python中完成吗?

我搜索了一下,发现这个stackoverflow问题解释了如何使用inspect从堆栈中读取名称。但是,我发现python不支持宏,因此不能使用与c程序相同的格式。

是否有某种机制可以支持这种类型的调试打印?我尝试过lambda,但在本例中,"函数名"打印为""。


您可以检查最后一帧以检索调用者名称,其余部分是简单的格式,类似于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import sys

def dprint(fmt=None, *args, **kwargs):
    try:
        name = sys._getframe(1).f_code.co_name
    except (IndexError, TypeError, AttributeError):  # something went wrong
        name ="<unknown>"
    print("[{}] {}".format(name, (fmt or"{}").format(*args, **kwargs)))

def testfunction1():
    dprint("Running {}", 1)

def testfunction2():
    dprint("Running {}", 2)

def main():
    dprint("Running {}", 0)
    testfunction1()
    testfunction2()
    return 0

if __name__ =="__main__":
    main()

# prints:
# [main] Running 0
# [testfunction1] Running 1
# [testfunction2] Running 2

我建议不要使用print,而是设置一个记录器。日志模块有一个funcName属性,可用于所有LogRecords。

然后您将得到(代码取自Zwer的答案):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import logging

def create_logger(app_name=None):
    logger = logging.getLogger(app_name or __name__)
    logger.setLevel(logging.DEBUG)
    log_format = '[%(asctime)-15s] [%(levelname)08s] (%(funcName)s %(message)s'
    logging.basicConfig(format=log_format)
    return logger

LOGGER = create_logger()

def testfunction1():
    LOGGER.info("Running %d", 1)

def testfunction2():
    LOGGER.error("Running %s", 2)

def main():
    LOGGER.debug("Running %03d", 0)
    testfunction1()
    testfunction2()

if __name__ =="__main__":
    main()

这将产生类似于:

1
2
3
[2017-06-13 19:41:45,677] [   DEBUG] (main) Running 000
[2017-06-13 19:41:45,677] [    INFO] (testfunction1) Running 1
[2017-06-13 19:41:45,677] [   ERROR] (testfunction2) Running 2


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import inspect
import sys
def DPRINT(fmt, *args):
    print"{} {} {}".format(sys._getframe(1).f_code.co_name, fmt, args)

    # below line is another way to get the name of a calling function
    # print"{} {} {}".format(inspect.stack()[1][3], fmt, args)

def testfunction1():
    DPRINT("Running: 1")

def testfunction2():
    DPRINT("Running: 2")

def main():
    DPRINT("Running: 0")
    testfunction1()
    testfunction2()

main()

我不知道这是否有帮助