kra*_*r65 29 python debugging line-numbers inspect
我目前正在用Python构建一个非常复杂的系统,当我调试时,我经常将简单的print语句放在几个脚本中.为了保持概述,我经常还要打印出print语句所在的文件名和行号.我当然可以手动执行,或者使用以下内容:
from inspect import currentframe, getframeinfo
print getframeinfo(currentframe()).filename + ':' + str(getframeinfo(currentframe()).lineno) + ' - ', 'what I actually want to print out here'
Run Code Online (Sandbox Code Playgroud)
它打印的东西像:
filenameX.py:273 - 我真的想在这里打印出来
为了使它更简单,我希望能够做到这样的事情:
print debuginfo(), 'what I actually want to print out here'
Run Code Online (Sandbox Code Playgroud)
所以我把它放到某个地方的函数中并试着这样做:
from debugutil import debuginfo
print debuginfo(), 'what I actually want to print out here'
print debuginfo(), 'and something else here'
Run Code Online (Sandbox Code Playgroud)
不幸的是,我得到:
debugutil.py:3 - what I actually want to print out here
debugutil.py:3 - and something else here
Run Code Online (Sandbox Code Playgroud)
它打印出我定义函数的文件名和行号,而不是我调用debuginfo()的行.这很明显,因为代码位于debugutil.py文件中.
所以我的问题实际上是:如何获取调用此debuginfo()函数的文件名和行号?欢迎所有提示!
Zer*_*eus 58
该函数inspect.stack()返回一个帧记录列表,从调用者开始并移出,您可以使用它来获取所需的信息:
from inspect import getframeinfo, stack
def debuginfo(message):
caller = getframeinfo(stack()[1][0])
print "%s:%d - %s" % (caller.filename, caller.lineno, message)
def grr(arg):
debuginfo(arg)
grr("aargh")
Run Code Online (Sandbox Code Playgroud)
输出:
example.py:8 - aargh
Run Code Online (Sandbox Code Playgroud)
小智 8
如果您将跟踪代码放在另一个函数中,并从主代码中调用它,那么您需要确保从祖父而不是父或跟踪函数本身获取堆栈信息
下面是一个 3 级深度系统的例子,以进一步阐明我的意思。我的主函数调用一个跟踪函数,它调用另一个函数来完成这项工作。
######################################
import sys, os, inspect, time
time_start = 0.0 # initial start time
def trace_libary_init():
global time_start
time_start = time.time() # when the program started
def trace_library_do(relative_frame, msg=""):
global time_start
time_now = time.time()
# relative_frame is 0 for current function (this one),
# 1 for direct parent, or 2 for grand parent..
total_stack = inspect.stack() # total complete stack
total_depth = len(total_stack) # length of total stack
frameinfo = total_stack[relative_frame][0] # info on rel frame
relative_depth = total_depth - relative_frame # length of stack there
# Information on function at the relative frame number
func_name = frameinfo.f_code.co_name
filename = os.path.basename(frameinfo.f_code.co_filename)
line_number = frameinfo.f_lineno # of the call
func_firstlineno = frameinfo.f_code.co_firstlineno
fileline = "%s:%d" % (filename, line_number)
time_diff = time_now - time_start
print("%13.6f %-20s %-24s %s" % (time_diff, fileline, func_name, msg))
################################
def trace_do(msg=""):
trace_library_do(1, "trace within interface function")
trace_library_do(2, msg)
# any common tracing stuff you might want to do...
################################
def main(argc, argv):
rc=0
trace_libary_init()
for i in range(3):
trace_do("this is at step %i" %i)
time.sleep((i+1) * 0.1) # in 1/10's of a second
return rc
rc=main(sys.argv.__len__(), sys.argv)
sys.exit(rc)
Run Code Online (Sandbox Code Playgroud)
这将打印如下内容:
$ python test.py
0.000005 test.py:39 trace_do trace within interface func
0.001231 test.py:49 main this is at step 0
0.101541 test.py:39 trace_do trace within interface func
0.101900 test.py:49 main this is at step 1
0.302469 test.py:39 trace_do trace within interface func
0.302828 test.py:49 main this is at step 2
Run Code Online (Sandbox Code Playgroud)
顶部的 trace_library_do() 函数是一个示例,您可以将其放入库中,然后从其他跟踪函数中调用它。相对深度值控制打印 python 堆栈中的哪个条目。
我展示了在该函数中提取了一些其他有趣的值,例如函数开始的行号、总堆栈深度和文件的完整路径。我没有展示它,但是函数中的全局和局部变量也可以在检查中使用,以及到你下面所有其他函数的完整堆栈跟踪。我上面显示的信息足以进行分层调用/返回时间跟踪。从这里开始创建您自己的源代码级调试器的主要部分实际上并没有那么远——而且大部分都只是坐在那里等待使用。
我敢肯定有人会反对我使用内部字段和检查结构返回的数据,因为很可能有访问函数为你做同样的事情。但是我通过在 python 调试器中逐步执行这种类型的代码找到了它们,它们至少在这里工作。我正在运行 python 2.7.12,如果您运行不同的版本,结果可能会非常好。
在任何情况下,我强烈建议您将检查代码导入到您自己的一些 Python 代码中,并查看它可以为您提供什么——特别是如果您可以在一个好的 Python 调试器中单步调试您的代码。您将学到很多关于 Python 工作原理的知识,并看到这门语言的好处,以及幕后发生的事情使之成为可能。
带有时间戳的完整源代码级跟踪是增强您对代码正在做什么的理解的好方法,尤其是在更多动态实时环境中。这种类型的跟踪代码的优点在于,一旦编写完成,您就不需要调试器支持来查看它。
| 归档时间: |
|
| 查看次数: |
10390 次 |
| 最近记录: |