Python AST 模块实战演示

 更新时间:2025年11月21日 17:14:45   作者:烟雨AC  
Python的ast模块提供了一种处理Python代码的强大工具,通过解析代码生成抽象语法树(AST),可以进行代码分析、修改和生成,接下来通过本文给大家介绍Python AST 模块实战教程,感兴趣的朋友跟随小编一起看看吧

Python 的 ast(Abstract Syntax Tree,抽象语法树)模块是一个用于处理 Python 代码的强大工具。它允许你将代码转换为一种结构化的树形表示,从而可以进行分析、修改甚至生成新的代码。这对于理解代码的内部结构、构建开发工具或进行代码自动化处理非常有帮助。

🔍 什么是抽象语法树(AST)

在深入了解 ast 模块之前,我们先简单理解一下抽象语法树(AST)的概念。当 Python 解释器执行代码时,它首先需要理解代码的结构。这个过程大致是:源代码 -> 词法分析(生成令牌流) -> 语法分析(生成 AST) -> 字节码 -> 执行。AST 就是源代码抽象语法结构的树状表示,它过滤掉了像空格、注释这类非本质的细节,专注于代码的逻辑结构。每个节点代表代码中的一个结构(例如,一个表达式、一个语句、一个函数定义等)。

ast 模块的核心作用就是在这棵“语法树”上工作,让你能在代码被编译成字节码之前,洞察和操作其本质。

🛠️ ast 模块的核心用法

ast 模块提供了一系列函数和类来创建、遍历和修改 AST。

1. 解析代码生成 AST

使用 ast.parse() 函数可以将字符串形式的 Python 代码解析成一棵 AST 的根节点(通常是 ast.Module 节点)。

import ast
code = """
def greet(name):
    print(f"Hello, {name}!")
"""
tree = ast.parse(code)  # 得到 AST

2. 查看 AST 结构

生成 AST 后,可以使用 ast.dump() 函数将其以文本形式打印出来,以便查看整个树的结构。

print(ast.dump(tree, indent=4))

这会输出一个结构化的文本,展示所有的节点、它们的属性以及嵌套关系。

3. 遍历 AST

要分析 AST,你需要遍历它的节点。ast 模块提供了两种主要方式:

  • 使用 ast.NodeVisitor 类:这是最常用和推荐的方法。你可以创建一个继承自 ast.NodeVisitor 的类,并为感兴趣的节点类型定义 visit_ 方法(例如 visit_FunctionDef 用于访问函数定义节点)。在方法中,你可以通过 self.generic_visit(node) 来继续遍历当前节点的子节点。
class MyVisitor(ast.NodeVisitor):
    def visit_FunctionDef(self, node):
        print(f"Found function: {node.name}")
        self.generic_visit(node)  # 继续遍历子节点
visitor = MyVisitor()
visitor.visit(tree)
  • 使用 ast.walk() 函数:这个函数会递归地遍历 AST 中的所有节点,但不关心节点的层级关系。它返回一个生成器,适合当你需要找到所有特定类型的节点时使用。
for node in ast.walk(tree):
    if isinstance(node, ast.FunctionDef):
        print(node.name)

4. 修改 AST

除了分析,你还可以修改 AST。这需要通过继承 ast.NodeTransformer 类来实现。它的使用方式和 NodeVisitor 类似,但关键区别在于,visit_ 方法需要返回一个节点。你可以返回:

  • 原节点:不做任何修改。
  • 新节点:替换原节点。
  • None:删除该节点。

一个经典的例子是将代码中的所有加法操作 + 替换为减法操作 -

class AddToSubTransformer(ast.NodeTransformer):
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Add):
            # 创建一个新的操作符节点,将加法改为减法
            node.op = ast.Sub()
        return self.generic_visit(node)  # 返回修改后的节点,并继续遍历其子节点
transformer = AddToSubTransformer()
new_tree = transformer.visit(tree)

重要提示:在创建新节点替换旧节点后,如果新节点缺少源代码位置信息(如行号、列偏移量),需要使用 ast.fix_missing_locations() 函数来修复,否则在编译时可能会出错。

5. 将 AST 编译回代码

修改完 AST 后,你可以通过内置的 compile() 函数将其编译成可执行的 Python 字节码,然后使用 exec()eval() 来运行它。

# 将修改后的 AST 编译成代码对象
code_obj = compile(new_tree, filename='<string>', mode='exec')
# 执行代码对象
exec(code_obj)

此外,从 Python 3.9 开始,标准库提供了 ast.unparse() 函数,可以直接将 AST 节点转换回可读的 Python 代码字符串。对于更早的版本,可以使用第三方库如 astor

6. 安全地求值表达式

ast 模块还提供了一个非常实用的函数 ast.literal_eval()。它可以安全地计算一个包含 Python 字面量(如字符串、数字、元组、列表、字典、布尔值等)的表达式字符串,并返回结果。与内置的 eval() 不同,它不会执行任意代码,因此安全得多,非常适合处理来自不可信来源的数据。

safe_result = ast.literal_eval("[1, 2, 3]")  # 结果是列表 [1, 2, 3]

💻 大厂笔试面试如何考察 ast

在大厂的笔试或面试中,对 ast 模块的考察通常不会要求你死记硬背所有的节点类型,而是更注重实践应用能力对 Python 机制的理解深度以及解决实际问题的思路

常见的考察方向

  • 基础概念理解
    • 可能会问:AST 在 Python 解释过程中处于哪个阶段?它和字节码有什么区别?
    • 或者:ast.literal_eval()eval() 有什么区别?为什么前者更安全?
  • 代码分析与审计
    • 静态代码检查:让你编写一个简单的检查器,使用 ast.NodeVisitor 来遍历代码,找出潜在问题。例如,检测是否使用了不安全的函数(如 evalexec),或者检查代码风格(如变量命名规范)。
    • 代码复杂度分析:通过分析函数定义、循环、条件分支等节点的数量和嵌套关系,来估算代码的复杂度。
  • 代码转换与自动化
    • 这是考察的重点和难点。面试官可能会给出一个具体的代码重构任务,让你使用 ast.NodeTransformer 来实现自动化。例如:
  • 重命名:将代码中所有特定变量名或函数名进行批量替换。
  • 逻辑替换:如前面提到的,将加法操作改为减法。
  • API 升级:假设某个库的 API 发生了变化,需要你写一个工具自动将旧代码中的函数调用更新为新形式。
  • 与网络安全结合
    • 尤其是在安全相关的岗位面试中。可能会给出一段代码,要求你分析其中可能存在的安全漏洞(如 SQL 注入、命令注入点),这需要你能够通过 AST 分析代码的数据流和控制流。

实例分析:面试题模拟

题目:请你使用 ast 模块,编写一个简单的静态分析工具,用于检测一段 Python 代码中是否使用了 eval() 函数。如果使用了,则输出警告信息。

考察点

  • 是否掌握 ast 的基本解析和遍历操作。
  • 是否熟悉 ast.NodeVisitor 的使用。
  • 能否识别函数调用节点(ast.Call)并判断其函数名。

参考实现

import ast
code = """
x = 1
result = eval('1 + 1')
print(eval('2+2'))
"""
class EvalDetector(ast.NodeVisitor):
    def visit_Call(self, node):
        # 检查节点是否是一个函数调用,并且函数名是一个标识符(Name)且id为'eval'
        if isinstance(node.func, ast.Name) and node.func.id == 'eval':
            print(f"Warning: Potential use of eval() found at line {node.lineno}")
        # 继续遍历子节点,以查找嵌套调用等情况
        self.generic_visit(node)
tree = ast.parse(code)
detector = EvalDetector()
detector.visit(tree)

输出

Warning: Potential use of eval() found at line 4
Warning: Potential use of eval() found at line 5

这个例子演示了如何使用 ast.NodeVisitor 来访问代码中的函数调用节点(ast.Call),并根据条件(函数名为 eval)进行判断和输出。

💎 总结与核心知识点

为了帮助你更好地记忆,我将 ast 模块的核心知识点整理成了下面的表格:

核心概念/操作关键函数/类说明与用途
解析代码ast.parse(source)将源代码字符串解析为 AST 根节点(ast.Module)。
查看结构ast.dump(node)将 AST 节点以字符串形式输出,用于调试。
遍历 ASTast.NodeVisitor通过继承此类并定义 visit_XXX 方法来有选择地访问节点。
遍历 ASTast.walk(node)递归遍历 AST 中的所有节点,不保留层级信息。
修改 ASTast.NodeTransformer通过继承此类,在 visit_XXX 方法中返回新节点来修改 AST。
编译执行compile(tree, ...)将 AST 编译为可执行的代码对象。
反解析ast.unparse(node) (Python 3.9+)将 AST 节点转换回等价的 Python 代码字符串。
安全求值ast.literal_eval()安全地求值字面量表达式(字符串、列表、数字等),避免任意代码执行风险。
修复位置ast.fix_missing_locations(node)为新建或修改的节点补充行号等位置信息,确保能正确编译。

到此这篇关于Python AST 模块实战解析的文章就介绍到这了,更多相关python ast 模块内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Python如何生成便签图片详解

    利用Python如何生成便签图片详解

    python现在火热的程度相信不用过多介绍了,下面这篇文章主要给大家介绍了关于利用Python如何生成便签图片的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • 解决django服务器重启端口被占用的问题

    解决django服务器重启端口被占用的问题

    今天小编就为大家分享一篇解决django服务器重启端口被占用的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Python3.4学习笔记之类型判断,异常处理,终止程序操作小结

    Python3.4学习笔记之类型判断,异常处理,终止程序操作小结

    这篇文章主要介绍了Python3.4学习笔记之类型判断,异常处理,终止程序操作,结合具体实例形式分析了Python3.4模块导入、异常处理、退出程序等相关操作技巧与注意事项,需要的朋友可以参考下
    2019-03-03
  • Python中将JSON数据写入文件的实现方法

    Python中将JSON数据写入文件的实现方法

    在Python开发中,JSON是一种轻量级的数据交换格式,常用于前后端数据交互、配置文件存储等场景,当我们需要将Python中的字典或列表等数据以JSON格式保存到文件时,就需要掌握如何将JSON数据写入文件的方法,所以本文给大家介绍了Python中将JSON数据写入文件的实现方法
    2025-06-06
  • Python利用Turtle绘制哆啦A梦和小猪佩奇

    Python利用Turtle绘制哆啦A梦和小猪佩奇

    turtle库是python的基础绘图库,经常被用来介绍编程知识的方法库,是标准库之一,利用turtle可以制作很多复杂的绘图。本文将为大家介绍通过turtle库绘制制哆啦A梦和小猪佩奇,感兴趣的小伙伴可以学习一下
    2022-04-04
  • Python三目运算符(三元运算符)用法详解(含实例代码)

    Python三目运算符(三元运算符)用法详解(含实例代码)

    三元运算符在Python里被称为条件表达式,这些表达式基于真(true)/假(false)的条件判断,在Python 2.4以上才有了三元操作,下面这篇文章主要给大家介绍了关于Python三目运算符(三元运算符)用法的相关资料,需要的朋友可以参考下
    2023-02-02
  • 浅谈Python黑帽子取代netcat

    浅谈Python黑帽子取代netcat

    本篇文章通过一个小小实例给大家分析了Python黑帽子取代netcat的过程以及相关知识点,对此有兴趣的朋友可以学习下。
    2018-02-02
  • Python实现SICP赋值和局部状态

    Python实现SICP赋值和局部状态

    这篇文章主要介绍了Python实现SICP 赋值和局部状态的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • pytorch模型存储的2种实现方法

    pytorch模型存储的2种实现方法

    今天小编就为大家分享一篇pytorch模型存储的2种实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • python操作RabbitMq的三种工作模式

    python操作RabbitMq的三种工作模式

    这篇文章主要为大家介绍了python操作RabbitMq的三种工作模式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04

最新评论