Abstract Syntax Trees即抽象语法树。Ast是python源码到字节码的一种中间产物,借助ast模块可以从语法树的角度分析源码结构。此外,我们不仅可以修改和执行语法树,还可以将Source生成的语法树unparse成python源码。因此ast给python源码检查、语法分析、修改代码以及代码调试等留下了足够的发挥空间。
1. AST简介
Python官方提供的CPython解释器对python源码的处理过程如下:
Parse source code into a parse tree (Parser/pgen.c)
Transform parse tree into an Abstract Syntax Tree (Python/ast.c)
Transform AST into a Control Flow Graph (Python/compile.c)
Emit bytecode based on the Control Flow Graph (Python/compile.c)
即实际python代码的处理过程如下:
源代码解析 --> 语法树 --> 抽象语法树(AST) --> 控制流程图 --> 字节码
上述过程在python2.5之后被应用。python源码首先被解析成语法树,随后又转换成抽象语法树。在抽象语法树中我们可以看到源码文件中的python的语法结构。
大部分时间编程可能都不需要用到抽象语法树,但是在特定的条件和需求的情况下,AST又有其特殊的方便性。
下面是一个抽象语法的简单实例。
Module(body=[
Print(
dest=None,
values=[BinOp( left=Num(n=1),op=Add(),right=Num(n=2))],
nl=True,
)])
2. 创建AST
2.1 Compile函数
先简单了解一下compile函数。
compile(source, filename, mode[, flags[, dont_inherit]])
source -- 字符串或者AST(Abstract Syntax Trees)对象。一般可将整个py文件内容file.read()传入。
filename -- 代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。
mode -- 指定编译代码的种类。可以指定为 exec, eval, single。
flags -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
flags和dont_inherit是用来控制编译源码时的标志。
func_def =\"""def add(x, y):
return x + y
print add(3, 5)"""
使用Compile编译并执行:
>>> cm = compile(func_def, '', 'exec')>>> exec cm
>>> 8
上面func_def经过compile编译得到字节码,cm即code对象,True == isinstance(cm, types.CodeType)。
compile(source, filename, mode, ast.PyCF_ONLY_AST) <==> ast.parse(source, filename='', mode='exec')
2.2 生成ast
使用上面的func_def生成ast.
r_node =ast.parse(func_def)print astunparse.dump(r_node) #print ast.dump(r_node)
下面是func_def对应的ast结构:
Module(body=[
FunctionDef(
name='add',
args=arguments(
args=[Name(id='x',ctx=Param()),Name(id='y',ctx=Param())],
vararg=None,