Python AST 模块

2025年1月11日 | 阅读 6 分钟

在本教程中,我们将学习如何使用 AST 来理解代码。

什么是 AST 模块?

Python 中的 AST(抽象语法树)模块提供了在结构层面与 Python 代码交互的工具。抽象语法树是源代码的抽象语法结构的树形表示。树中的每个节点代表源代码中出现的构造。

AST 模块允许您将 Python 代码解析为其相应的 AST,以编程方式对其进行操作,然后将其转换回可执行的 Python 代码。这对于代码分析、代码生成、重构以及构建自定义解释器或编译器等任务非常有用。

您是否曾想过 Python 代码是如何运行的?它背后有什么魔法吗?

对于不知道的人来说,Python 解释器负责运行 Python 代码。它遵循预先编写的指令,将 Python 代码转换为机器可以运行的指令。

以下是将 Python 代码转换为机器代码的过程。

当我们运行代码时,它会被解析成更小的块,称为标记。这些标记是根据预定义的规则生成的,这些规则区分关键字和文字等元素。例如,`else` 被识别为控制流标记,而 `5` 是数字文字。此标记化过程有助于解释器或编译器正确理解和执行代码。

这些标记存储在一个列表中,经过转换以构建抽象语法树(AST)。AST 是根据 Python 语言的语法链接在一起的节点的集合。

编译器可以从 AST 生成称为**二进制代码**的低级指令。这段代码非常通用,计算机可以轻松运行。

当解释器收到类似字节码的指令时,解释器就可以运行代码了。字节码负责调用操作系统中的函数,该函数最终会与 CPU 和内存交互以运行程序。

上述描述是解释器使用 AST 运行 Python 代码的粗略草图。

代码编译模式

有三种模式可用于编译代码。它们如下。

  • exec - 此模式用于执行正常的 Python 代码。
  • eval - 此模式用于评估 Python 表达式,并在评估后返回结果。
  • single - 此模式像 Python shell 一样工作,一次执行一个语句。

执行 Python 代码

使用 AST 模块,我们可以运行 Python 代码。让我们看下面的例子。

示例 -

输出

<_ast.Module object at 0x0000010B889A6AC0>
Hello Learner! Welcome to JavaTpoint

评估 Python 表达式

AST 模块允许我们评估 Python 表达式并从表达式返回结果。让我们看下面的例子。

示例 -

输出

14
Expression(body=BinOp(left=Constant(value=6, kind=None), op=Add(), right=Constant(value=8, kind=None)))

创建多行 AST

在前面的示例中,我们看到了单行 AST 以及如何转储它们。现在,我们将学习如何创建多行 AST。首先,让我们看下面的例子。

示例 -

输出

Module(body=[Assign(targets=[Name(id='subjects', ctx=Store())], value=List(elts=[Constant(value='computer science', kind=None), Constant(value='alorithm', kind=None)], ctx=Load()), type_comment=None), Assign(targets=[Name(id='name', ctx=Store())], value=Constant(value='Ricky', kind=None), type_comment=None), For(target=Name(id='fruit', ctx=Store()), iter=Name(id='fruits', ctx=Load()), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Constant(value='{} learn {}', kind=None), attr='format', ctx=Load()), args=[Name(id='name', ctx=Load()), Name(id='subjects', ctx=Load())], keywords=[])], keywords=[]))], orelse=[], type_comment=None)], type_ignores=[])

NodeTransformer 和 NodeVisitor

NodeTransformer 类用于获取不同的类型并根据我们的需求进行修改。ast 模块还提供了 NodeVisitor 类,它帮助我们在遍历树的每次时调用 visit 函数。以便我们可以更精确地控制节点,让我们看下面的例子。

示例 - 1

输出

Welcome to the Javatpoint

解释 -

在上面的代码中,我们导入了 **ast 模块**来解析代码。然后,我们定义了继承了 **NodeVisitor** 类的 **Visitor** 类。每次找到字符串节点时,它都会被转换并添加前缀。

我们也可以在直接运行源代码时使用该模块。让我们看下面的例子。

示例 - 2

输出

{'from': ['pprint'], 'import': ['ast']}

解释 -

上面的代码将 Python 文件转换为抽象语法树。然后我们分析树以获取有用的信息。

我们以读取模式打开了一个 Python 文件,然后创建了一个名为 **ast_tree** 的 AST。然后,**parse()** 函数处理了所有标记,遵循了所有语言规则,并构建了一个包含许多有用信息的树数据结构。

树只不过是节点的集合,其中树变量引用了“根”节点。因此,我们可以访问树中的每个节点并执行操作。但是,首先,我们访问每个节点并处理数据。

分析 AST

一旦我们得到树,分析器就遵循访问者模式。使用 NodeVisitor 类,我们可以跟踪 Python 中的任何节点。我们需要实现一个名为 **visit_<node type>** 的方法来访问特定类型的节点。在前面的示例中,我们使用了以下脚本。

示例 -

将 AST 用作分析工具

Python 代码转换为字节码后,人类就无法阅读了。但它使解释器更快,这意味着字节码是为机器设计的,而不是为人类设计的。

AST 包含足够结构化的信息,这使得它们在学习 Python 代码方面很有用。但是,AST 仍然不是用户友好的,但它们比字节码表示更容易理解。

何时使用 Python AST 模块?

Python AST 模块在需要分析或操作 Python 代码的几种场景中都很有用。以下是一些常见用例:

1. 代码分析

  • 静态代码分析:在不执行代码的情况下,检查代码是否存在样式问题、潜在错误或是否符合编码标准。
  • 代码度量:收集有关代码复杂度、函数定义或代码覆盖率的信息。

2. 代码转换

  • 重构:自动重构代码,例如重命名变量或函数、重组代码块或优化代码。
  • 代码生成:根据现有代码模式或模板动态生成新代码。

结论

我们已经学习了 Python 中的 ast 模块,该模块负责运行 Python 代码。然后,我们从 Python 代码构建了 AST 树,并使用 **NodeVisitor** 类对 AST 进行了分析。