Python进阶之-ast使用详解

embedded/2024/10/18 7:54:36/

✨前言:

ast_1">🌟什么是ast?

ast模块在Python中用于将源码转换成抽象语法树(Abstract Syntax Trees,AST)。通过AST,我们可以读取、修改、分析Python代码。本质上,它将源码转化为树形结构,节点代表语法构造,如表达式、语句等。这对于编写代码分析、优化工具或自动代码生成等任务非常有用。
抽象语法树(AST)组成部分
Expression: 在Python的AST中,Expression节点表示一个表达式。这里,它是整个AST的根节点。Expression节点有一个body属性,用于存储表达式的主体。body=BinOp(…): body属性包含一个BinOp节点,表示一个二元操作(binary operation)。二元操作就是涉及两个操作数的运算,比如加法、减法等。left=Constant(value=2): 在BinOp节点中,left属性表示左侧的操作数。

🌟基本使用

首先,使用import ast命令导入ast模块。

⭐️例1:解析表达式
python">#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/5/4
# @Author  : Summer
# @File    : test
# @describe:
"""
import astexpression = "(1 + 2) * 3"
tree = ast.parse(expression, mode='eval')print(ast.dump(tree, indent=4))
# Expression(body=BinOp(left=BinOp(left=Constant(value=1, kind=None), op=Add(),
# right=Constant(value=2, kind=None)), op=Mult(), right=Constant(value=3, kind=None)))

该示例中,先通过ast.parse函数解析字符串表达式。mode='eval’表示这是一个表达式。然后利用ast.dump函数打印出该表达式的树形结构,indent=4参数使输出更加易于阅读。

Expression:表示这是一个表达式节点。在AST种,Expression用于包装一个表达式,这里它是根节点。
body:这是Expression节点的主体,它包含了真正的运算逻辑。
BinOp:代表二元操作的节点,即涉及两个操作数的运算。在这个例子中,有两层BinOp。
第一层BinOp(外层)代表乘法操作(Mult()),它的两个操作数分别是: left=BinOp()
(内层):这个代表加法操作(Add())。具体包含: left=Constant(value=1,
kind=None):这是一个常量节点,表示整数1。 right=Constant(value=2,
kind=None):这也是一个常量节点,表示整数2。 这表明内层BinOp表示的表达式是1 + 2。 第一层BinOp的另一个操作数是:
right=Constant(value=3, kind=None):这是一个表示整数3的常量节点。
op:这个属性表示操作类型,Add()是加法操作,Mult()是乘法操作。 因此,这整个Expression节点表示的表达式是:(1 +
2) * 3。 kind=None:在Constant节点中,kind属性表示常量的字面种类。

⚠️注意:indent=4参数是python3.9版本之后引入的,需要注意自己的python版本。

⭐️例2:遍历AST节点

要访问AST的每个节点,最直接的方法是使用ast.NodeVisitor类。下面我们实现一个简单的访问者,计算AST树中出现的所有Num节点的总和:

python">#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/5/4
# @Author  : Summer
# @File    : test
# @describe:
"""
import astclass SumNumbers(ast.NodeVisitor):def __init__(self):self.total = 0def visit_Num(self, node):self.total += node.nself.generic_visit(node)expression = "1 + 2 + (3 * 4)"
tree = ast.parse(expression, mode='eval')
visitor = SumNumbers()
visitor.visit(tree)print(visitor.total)  # 10

上例中,SumNumbers类继承自ast.NodeVisitor,通过定义visit_方法来处理特定类型的节点。这里,我们处理Num节点,即数值。
👉为什么输出是10?
对于表达式 “1 + 2 + (3 * 4)”,简化的AST遍历如下:
数值 1(Constant节点)
数值 2(Constant节点)
数值 3(Constant节点)
数值 4(Constant节点)
根据此逻辑,总结如下:

1出现1次。
2出现1次。
3出现1次(作为乘法操作的一部分)。
4出现1次(作为乘法操作的一部分)。
累加这些数值得到的total是10,实际上,AST保持了源码的结构,对于(3 * 4),它会以3和4两个独立的Constant节点存在于树中,同时由BinOp节点表示这个乘法操作。

⭐️例3:修改AST节点

若要修改AST,可以使用ast.NodeTransformer类。以下例子把所有的数字乘以2:

python">#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/5/4
# @Author  : Summer
# @File    : test
# @describe:
"""
import astclass DoubleNumbers(ast.NodeTransformer):def visit_Num(self, node):return ast.copy_location(ast.Num(n=node.n * 2), node)expression = "1 + 2"
tree = ast.parse(expression, mode='eval')
transformer = DoubleNumbers()
new_tree = transformer.visit(tree)print(ast.dump(new_tree)) 

这个例子通过继承ast.NodeTransformer并重写visit_Num方法,来修改数值节点。ast.copy_location帮助保持原节点的源代码位置信息。

astAttribute_119">⭐️ast.Attribute

ast.Attribute 类型在 Python 的抽象语法树(AST)中用于表示对属性的访问,例如在访问对象的属性或方法时。举一个简单的例子,当你有一个像 object.attribute 这样的代码时,可以通过 ast 模块来解析和理解这种结构。

先看一个具体的代码示例,然后解析它:

python">#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/5/4
# @Author  : Summer
# @File    : test
# @describe:
"""import ast# 假设我们有如下代码,我们想要解析它
code = """
class MyClass:def method(self):passobj = MyClass()
obj.method()
"""# 使用 ast.parse 将代码字符串解析为 AST
parsed_code = ast.parse(code)# 定义一个访问者类,该类继承自 ast.NodeVisitor
class MyVisitor(ast.NodeVisitor):def visit_Attribute(self, node):print(f"Found an attribute access: {node.attr}")self.generic_visit(node)  # 继续访问节点的子节点# 实例化我们的访问者,并访问解析得到的 AST
visitor = MyVisitor()
visitor.visit(parsed_code)  # Found an attribute access: method

在这个例子中,我们定义了一个名为 MyClass 的类和一个该类的实例 obj。随后,我们通过 obj.method() 调用类的一个方法。我们的目标是通过访问 AST 来找到这种对属性(在这个案例中是方法)的访问。这里,当实例化 MyVisitor 类并调用它的 visit 方法时,它会遍历整个 AST。每当遇到 ast.Attribute 类型的节点时,visit_Attribute 方法将被调用,打印出我们正在访问的属性的名字。输出结果为 Found an attribute access: method 这表明,我们成功地识别了代码中对属性(或方法)method 的访问。

astConstant_163">⭐️ ast.Constant

ast.Constant 是 Python 抽象语法树(AST)中表示字面量值的节点类型。这包括数值字面量(如整数、浮点数)、字符串字面量、布尔值(True 和 False)以及 None。下面通过一个例子介绍如何使用 ast 模块来解析这些常量,并展示如何访问它们。
假设我们有一段包含字面量值的 Python 代码,我们希望解析这段代码并识别出所有的常量值。

python">#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/5/4
# @Author  : Summer
# @File    : test
# @describe:
"""import ast# 定义一个包含各种常量的代码字符串
code = """
x = 10
y = 3.14
name = "Python"
flag = True
nothing = None
"""# 使用 ast.parse 将代码字符串解析为 AST
parsed_code = ast.parse(code)# 定义一个访问者类,该类继承自 ast.NodeVisitor
class FindConstants(ast.NodeVisitor):def visit_Constant(self, node):print(f"Found a constant: {node.value}")self.generic_visit(node)  # 继续访问节点的子节点# 实例化我们的访问者,并访问解析得到的 AST
finder = FindConstants()
finder.visit(parsed_code)

在这个例子中,我们首先定义了一个包含不同类型常量的代码字符串,随后通过 ast.parse 函数将其解析为 AST。然后,我们定义了一个 FindConstants 类,它是 ast.NodeVisitor 的子类,用于遍历 AST。对于每一个遇到的 ast.Constant 节点,我们将其值打印出来。
输出:

python">Found a constant: 10
Found a constant: 3.14
Found a constant: Python
Found a constant: True
Found a constant: None

这表示我们成功识别并访问了代码中的所有常量。通过这种方式,使用 ast 模块可以使我们能够对 Python 代码进行静态分析,例如识别代码中的硬编码值、分析代码的结构等。ast.NodeVisitor 提供了一种强大的机制,允许我们通过重写其方法来自定义对不同类型节点的访问行为,从而实现对 AST 的遍历和操作。

ast_214">🌟ast常见用途

静态代码分析:分析代码结构,检查编码规范或查找潜在的bug。
代码优化:修改AST,进行诸如常量传播、死码删除等简单优化。
代码生成:根据特定的逻辑生成新的Python代码片段。
注意事项
使用ast时要小心执行任意的Python代码,特别是使用ast.literal_eval时,因为它比eval安全,但仍需谨慎对待输入源。
修改AST需要理解Python的语法结构,否则可能产生语法错误的代码。
ast模块是Python语言强大的特性之一。它不仅允许代码自省和动态修改,还可以用于构建复杂的编程工具和框架。


http://www.ppmy.cn/embedded/32977.html

相关文章

【玩转Google云】GCP Kubernetes Engine (GKE) 深入解析

Google Kubernetes Engine (GKE) 作为 Google Cloud Platform (GCP) 提供的托管式 Kubernetes 服务,为开发者和运维人员提供了一条通往云原生应用的便捷之路。本文将深入剖析 GKE 的核心优势和主要功能,带您领略其如何简化 Kubernetes 管理、提升应用可靠性与可扩展性,并保障…

VMware虚拟机中ubuntu使用记录(6)—— 如何标定单目相机的内参(张正友标定法)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、张正友相机标定法1. 工具的准备2. 标定的步骤(1) 启动相机(2) 启动标定程序(3) 标定过程的操作(5)可能的报错 3. 标定文件内容解析 前言 张正友相机标定法…

JVM笔记1--Java内存区域

1、运行时数据区域 从上图可以看出来,Java虚拟机运行时数据区域整体上可以分成5大块: 1.1、程序计数器 程序计数器是一块较小的内存空间。它可以看做当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里,字节码解释器工作时就是…

如何打包Apk适配32和64位

一个表格了解lib下的文件夹 .so文件描述armeabi-v7a第七代及以上的ARM处理器,2011年以后生产的大部分Android设备都使用。arm64-v8a第8代、64位ARM处理器,很少设备,三星GalaxyS6是其中之一。armeabi第5代、第6代的ARM处理器,早期…

服务器清理内存tmp

因为我们的服务器是公用的tmp内存有限 在非root用户权限下可以删除文件rm -rf 目录名字 Linux 递归删除文件夹和文件——rm命令_递归删除rm-CSDN博客 参考这个文件

[C++][数据结构]哈希1:哈希函数的介绍与线性探测的实现

前言 学完了二叉树,我们要学当前阶段数据结构的最后一个内容了:哈希!! 引入 先来介绍两个用哈希封装的两个容器:unordered_map unordered_set 与map和set的不同: map/set是双向迭代器,而另…

密码学python库PBC安装使用

初始化 使用环境云服务器(移动云可以免费使用一个月) 选择ubuntu18.04-64位 第一次进入linux命令行之后是没有界面显示的,需要在命令行下载。 这里按照其他云平台操作即可:Ubuntu18.04 首次使用配置教程(图形界面安装) 记录好登录…

Cisco WLC 2504控制器重启后所有AP掉线故障-系统日期时间

1 故障描述 现场1台WLC 2504控制器掉电重启后,所有AP均无线上线, 正常时共有18个AP在线,而当前为0 AP在线数量为0 (Cisco Controller) >show ap sumNumber of APs.................................... 0Global AP User Name..........…