您可以使用ast模块,但仍然需要源代码。如果您只有字节码,您必须使用类似uncompyle6的方法来取回源代码—因为您是自动执行此操作的,因此源代码是否被混淆并不重要。在
假设您有这样一个模块:def foo(x):
if x > 100:
print('big')
else:
print('small')
if __name__ == '__main__':
foo(5)
foo(500)
如果你执行foo,你会得到:
^{pr2}$
现在,如果测试是True,则要打印每个if语句的test子句。让我们从导入foo开始:>>> import foo
然后获取源代码:>>> source = inspect.getsource(foo)
允许解析源代码以获取抽象语法树:>>> tree = ast.parse(source)
下一步是定义将修改树的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)
为了修改树,我们让IfTransformer访问所有节点:>>> IfTransformer().visit(tree)
然后可以编译和执行新源代码:>>> exec(compile(tree, 'foo.py', 'exec'))
(__name__ == '__main__')
small
(x > 100)
big
对于每个测试为True的if子句,都会打印测试。像你这样聪明的人可以从这里搞清楚一切。在