【问题标题】:Including the current method name when printing in Python在 Python 中打印时包含当前方法名称
【发布时间】:2017-06-13 13:16:35
【问题描述】:

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

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

使用时,当前函数将被添加到每次打印之前,在运行时提供更多有用的调试信息。比如下面的代码

#include <stdio.h>

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

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

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

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

会输出:

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

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

我搜索了一下,发现this StackOverflow 问题解释了如何使用inspect 从堆栈中读取名称。但是,我发现Python不支持宏,所以不能使用和我的C程序一样的形式。

是否有某种机制可以支持这种类型的调试打印?我尝试了 lambdas,但在这种情况下,“函数名”打印为“”。

【问题讨论】:

  • 它仍然不清楚你的期望
  • @AmeyYadav,更新了问题。
  • 你能把你尝试过的示例代码放上来吗?从那里开始通常很容易。为了快速回答,是的,你可以,检查 python 中装饰器的使用。你可以包装一个函数来调试它的名字。

标签: python function debugging inspect


【解决方案1】:

您可以检查最后一帧以检索来电者姓名,剩下的就是简单的格式,例如

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

【讨论】:

    【解决方案2】:

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

    然后您将拥有(代码取自 zwer 的答案):

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

    这将产生类似于:

    [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
    

    【讨论】:

    • 一个更强大的答案
    【解决方案3】:
    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()
    

    我不知道这是否有帮助

    【讨论】:

    • 哦.. 伙计。当我阅读您的解决方案时,它是如此明显。如果您可以从堆栈中读取当前函数的名称,那么您也可以从堆栈中读取调用者的名称..
    • 确实@sherrellbc
    • @AmeyYadav - 读取整个堆栈只是为了抓取最后一帧是非常浪费的。
    • @zwer 出于明显的原因,我没有考虑优化答案,我只是新的一种方法,可能还有一百万。
    猜你喜欢
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 2019-01-07
    • 2020-01-11
    相关资源
    最近更新 更多