如何在 python 程序中注入代码,以便它们可以打印 if 语句中的条件?

x86*_*-64 0 python instrumentation python-2.7

我正在寻找一种方法来检测(在其中注入代码)python 程序。例如,如果程序满足if条件x > 2,我想在打印到控制台的条件print后面自动添加一条语句。ifx > 2

该程序的源代码不可用。

Pau*_*ine 5

您可以使用该ast模块,但仍然需要源代码。如果您只有字节码,则必须使用类似uncompyle6之类的东西才能取回源代码 - 因为您是自动执行此操作,所以源代码是否被混淆并不重要。

假设你有一个这样的模块:

def foo(x):
    if x > 100:
        print('big')
    else:
        print('small')


if __name__ == '__main__':
    foo(5)
    foo(500)
Run Code Online (Sandbox Code Playgroud)

如果你执行 foo,你会得到:

small
big
Run Code Online (Sandbox Code Playgroud)

if现在,如果测试是 ,您想要打印每个语句的测试子句True。让我们从导入 foo 开始:

>>> import foo
Run Code Online (Sandbox Code Playgroud)

然后获取源码:

>>> source = inspect.getsource(foo)
Run Code Online (Sandbox Code Playgroud)

让我们解析源代码以获得抽象语法树:

>>> tree = ast.parse(source)
Run Code Online (Sandbox Code Playgroud)

下一步是定义一个将修改树的 NodeTransformer:

>>> class IfTransformer(ast.NodeTransformer):
         def visit_If(self, node):
             new_node = ast.Expr(value=ast.Call(
                  func=ast.Name(id='print', ctx=ast.Load()), 
                  args=[ast.Str(s=astunparse.unparse(node.test))], 
                  keywords=[]
             ))
             node.body.insert(0, new_node)
             return ast.fix_missing_locations(node)
Run Code Online (Sandbox Code Playgroud)

为了修改树,我们访问IfTransformer所有节点:

>>> IfTransformer().visit(tree)
Run Code Online (Sandbox Code Playgroud)

然后你可以编译并执行你的新源:

>>> exec(compile(tree, 'foo.py', 'exec'))
(__name__ == '__main__')

small
(x > 100)

big
Run Code Online (Sandbox Code Playgroud)

if对于测试为 True 的每个子句,您都会打印测试。像你这样聪明的人,从这里就能弄清楚一切。

观看Pycon 2011 的视频