如何在跟踪Python函数时获得调用表达式?

2024-07-01 07:10:00 发布

您现在位置:Python中文网/ 问答频道 /正文

在跟踪函数内部调试函数调用时,是否可以以某种方式检索调用表达式?在

我可以从回溯对象中得到调用行号,但是如果在那一行上有多个函数调用(可能是对同一个函数的调用)(例如,在一个更大的表达式中作为子表达式),那么我如何知道这个调用来自何处?我会很高兴即使偏移源行的开始。在

traceback.tb_lasti似乎提供了更多的granual context(最近尝试的字节码的索引)--是否有可能将字节码与其确切的源范围连接起来?在

编辑:只是为了澄清——我需要从调用源代码行提取特定(子)表达式(调用站点)。在


Tags: 对象函数编辑字节源代码表达式方式context
3条回答

不幸的是,编译后的字节码丢失了列偏移量;字节码索引到行号的映射包含在co_lnotab行号表中。dis模块是查看字节码并解释co_lnotab的好方法:

>>> dis.dis(compile('a, b, c', '', 'eval'))
  1           0 LOAD_NAME                0 (a)
              3 LOAD_NAME                1 (b)
              6 LOAD_NAME                2 (c)
              9 BUILD_TUPLE              3
             12 RETURN_VALUE        
  ^-- line number

但是,没有什么能阻止我们搞乱行号:

^{pr2}$

由于直接编译代码应该与通过ast.parse编译相同,并且由于弄乱行号不应该影响生成的字节码(除了co_lnotab),您应该能够:

  • 找到源文件
  • ast.parse解析它
  • munge ast中的行号以包括列偏移量
  • 编译ast
  • 使用tb_lasti搜索munged co_lnotab
  • 将蒙版行号转换回(行号,列偏移量)

我知道这是巫术,但我昨天发布了一个类似的问题,但没有先看到这个问题。所以为了防止有人感兴趣,我用一种不同于公认答案的方式来解决我的问题,在Python3中使用inspectast模块。它仍然是为了调试和教育目的,但它做到了。在

答案很长,所以here is the link

回溯帧也有行号:

lineno = traceback.tb_lineno

您还可以访问code对象,该对象将具有名称和文件名:

^{pr2}$

您可以使用文件名和行号,加上帧全局参数和^{} module将其有效地转换为正确的源代码行:

linecache.checkcache(filename)
line = linecache.getline(filename, lineno, traceback.tb_frame.f_globals)

这就是^{} module在任何情况下用于将回溯转换为有用信息的方法。在

由于字节码只有一个行号与之关联,所以不能直接将字节码引回到源代码行的精确部分;您必须自己解析该行,以确定每个部分将发出的字节码,然后将其与代码对象的字节码相匹配。在

您可以使用^{} module来实现这一点,但不能逐行执行,因为您需要范围上下文来为本地、单元格和全局名称查找生成正确的字节码。在

相关问题 更多 >

    热门问题