我目前正在用Python构建一个相当复杂的系统,在调试时,我经常将简单的print语句放在几个脚本中。为了保持概览,我通常还想打印出print语句所在的文件名和行号。当然,我可以手动完成,或者使用类似这样的东西:
from inspect import currentframe, getframeinfo
print getframeinfo(currentframe()).filename + ':' + str(getframeinfo(currentframe()).lineno) + ' - ', 'what I actually want to print out here'
它将打印类似于:
filenameX.py:273 - what I actually want to print out here
为了使它更简单,我希望能够做到这样的事情:
print debuginfo(), 'what I actually want to print out here'
所以我把它放到一个函数里,试着做:
from debugutil import debuginfo
print debuginfo(), 'what I actually want to print out here'
print debuginfo(), 'and something else here'
不幸的是,我得到:
debugutil.py:3 - what I actually want to print out here
debugutil.py:3 - and something else here
它打印出我定义函数的文件名和行号,而不是我调用debuginfo()
的那一行。这是显而易见的,因为代码位于debugutil.py
文件中。
所以我的问题其实是:如何获取调用此debuginfo()函数的文件名和行号?
7条答案
按热度按时间jaql4c8m1#
函数
inspect.stack()
返回一个帧记录列表,从调用者开始,向外移动,您可以使用它来获取所需的信息:输出:
fcg9iug32#
如果您将跟踪代码放在另一个函数中,并从主代码调用它,那么您需要确保从祖父级(而不是父级或跟踪函数本身)获取堆栈信息
下面是一个3级深度系统的例子,以进一步阐明我的意思。我的main函数调用了一个跟踪函数,这个跟踪函数又调用了另一个函数来完成这项工作。
这将打印如下内容:
顶部的trace_library_do()函数是一个例子,您可以将其放入库中,然后从其他跟踪函数调用它。相对深度值控制打印python堆栈中的哪个条目。
我展示了在该函数中提取其他一些有趣的值,如函数开始的行号、总堆栈深度和文件的完整路径。我没有展示它,但函数中的全局和局部变量也可以在inspect中使用,以及对所有其他函数的完整堆栈跟踪。我上面展示的信息已经足够用来进行分层调用/返回时间跟踪了。实际上,从这里开始创建自己的源代码级调试器的主要部分并没有那么远--而且大多数都只是坐在那里等待使用。
我确信有人会反对我使用内部字段和检查结构返回的数据,因为很可能有访问函数为您做同样的事情。但我是通过在python调试器中单步调试这种类型的代码来发现它们的,它们至少在这里可以工作。我运行的是python 2.7.12,如果你运行的是不同的版本,你的结果可能会很糟糕。
在任何情况下,我强烈建议您将inspect代码导入到自己的一些python代码中,并查看它可以为您提供什么-特别是如果您可以在一个好的python调试器中单步执行代码。你将学到很多关于python如何工作的知识,并看到这门语言的好处,以及幕后发生了什么使之成为可能。
使用时间戳进行完整的源代码级跟踪是增强对代码正在做什么的理解的一种很好的方法,特别是在动态真实的环境中。这种类型的跟踪代码的优点在于,一旦编写好,您不需要调试器支持就可以看到它。
monwx1rj3#
使用字符串插值并显示调用方的函数名来更新已接受的答案。
uhry853o4#
traceprint包现在可以为您做到这一点:
PyCharm将自动使文件链接可点击/可跟踪。
通过
pip install traceprint
安装。tuwxkamq5#
只要把你发布的代码放到一个函数中:
然后按你想要的方式使用它:
我建议你把这个函数放在一个单独的模块中,这样你就可以在每次需要的时候重用它。
ckx4rj1h6#
发现这个问题有点相关的问题,但我想更多的细节re:执行(我不想安装整个调用图包)。
如果需要更详细的信息,可以使用标准库模块traceback检索完整的回溯,并使用
traceback.extract_stack()
存储堆栈对象(元组列表),或者使用traceback.print_stack()
打印它。这个比较适合我的需要,希望对别人有帮助!dfuffjeb7#
您可以使用logging模块中内置的python findCaller findCaller函数,并将stacklevel argument 设置为2。
E.x.:
将输出
'file_name':'C:\code\test_caller_info. py','line_no':9,'func_name':'','stack_info':无}