改进python中的堆栈跟踪钩子

所有, 我有一个类似问题2617120的问题,在这里找到:     如何使用traceit报告函数输入变量 提问者想要通过跟踪钩子执行时如何制作python打印输出函数参数的指针。 我正在寻找与此类似的东西,但有一点扭曲。我没有将所有数据转储出来,而是在运行代码时评估代码,并打印出任何已知的变量。例如,使用以下代码:
for modname in modnames:                   

if not modname or '.' in modname:      
     continue                                                                    
...                                  
跟踪挂钩会导致打印出以下内容:
for modname in modnames:                | for init in init,., encoding
                                        |
if not modname or '.' in modname:       | if not init or '.' in init
     continue                           |     continue
if not modname or '.' in modname:       | if not . or '.' in .
...                                     |
其中代码行根据运行帧进行插值。我已经在perl中完成了这项工作,在某些情况下它是救生员。 任何人都有关于在python中执行此操作的最佳方法的想法?我有自己的想法,但我想听听人们的想法(如果他们有任何预先制定的解决方案) 这里,btw是参考代码:
import sys
import linecache
import random

def traceit(frame, event, arg):
    if event == "line":
        lineno = frame.f_lineno
        filename = frame.f_globals["__file__"]
        if filename == "<stdin>":
            filename = "traceit.py"
        if (filename.endswith(".pyc") or
            filename.endswith(".pyo")):
            filename = filename[:-1]
        name = frame.f_globals["__name__"]
        line = linecache.getline(filename, lineno)
        print "%s:%s:%s: %s" % (name,  lineno,frame.f_code.co_name,line.rstrip())
    return traceit


def main():
    print "In main"
    for i in range(5):
        print i, random.randrange(0, 10)
    print "Done."

sys.settrace(traceit)
main()
    
已邀请:
这里有一个快速入侵,可能会给你一些启动,给出
line
中的一行文本和
frame
中的当前堆栈帧(顺便说一下,这意味着是
traceit
的内部函数)。
import re
from types import *

def interpolatevar(matchobj):
    excludetypes = set((NoneType, TypeType, FunctionType, LambdaType, ClassType,
                    CodeType, InstanceType, MethodType, BuiltinFunctionType,
                    BuiltinMethodType))

    var = matchobj.group(0)
    basevar = var.split(".")[0]
    if basevar in frame.f_code.co_names or basevar in frame.f_code.co_varnames:
        if basevar in frame.f_globals or basevar in frame.f_locals:
            val = eval(var, frame.f_globals, frame.f_locals)
            if type(val) not in excludetypes:
                return repr(val)
    return var

line = re.sub(r"[A-Za-z_][A-Za-z0-9_]*(.[A-Za-z_][A-Za-z0-9_]*)*", 
              interpolatevar, line)
由于这使用正则表达式来查找标识符,所以即使它们在字符串文字中,它也会愚蠢地找到它们,但标识符必须实际用于函数并在本地或全局范围内定义。 它确实处理对象属性访问(例如
foo.bar
将被该值替换),我最初发布的版本不会,并且它会过滤掉各种类型的值,因为用
<function foo at 0x02793470>
代替ѭ8并不能真正告诉你很多你没有已经知道。 (排除列表很容易定制,当然,如果您对这些类型的某些值感兴趣,或者您可以从
types
模块中添加其他值。) 从长远来看,我认为查看该行的字节码可能是有利可图的,因为通过这种方式更容易识别哪些令牌实际上是标识符。
ast
模块对于生成语句的解析树也可能很有用,它可以让你弄清楚标识符是什么,但是当你一次只看到一行时,这对条件和循环来说是有问题的。     

要回复问题请先登录注册