Python-AST语法树

news2024/11/20 9:27:05

一、抽象语法树

1、什么是抽象语法树

在计算机科学中,抽象语法树abstract syntax tree ,AST),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。AST是编译器或解释器在处理源代码时所使用的一种中间表示形式,在编译和代码生成过程中起着关键作用。

之所以说语法是「抽象」的,是因为这里的语法并不会表示出真实语法中出现的每个细节。

AST中的每个节点表示源代码中的一个语法构造,如变量声明、表达式、函数调用、控制结构等。树的根节点通常表示整个源代码文件,而子节点表示具体的语法元素及其关系。例如,一个函数声明的AST节点可能包含多个子节点,如函数名、参数列表和函数体等。

2、使用场景

python 和 Java 类似,解释器实际上分为两部分:编译器和虚拟机,先将代码编译成字节码,然后再由虚拟机执行。

在编译时,主要用途包括:

  1. 语法检查:编译器可以通过遍历AST来检查源代码中是否存在语法错误。
  2. 语义分析:编译器可以使用AST来分析源代码的语义,例如识别类型错误、作用域错误等。
  3. 优化:编译器可以通过对AST进行变换和简化,实现源代码的优化。
  4. 代码生成:编译器可以根据AST生成目标代码,例如汇编语言或机器代码。

在实际应用中,AST除了用于编译器或解释器,还被用于诸如代码重构、静态分析和代码格式化等工具和技术中。

编译器和解释器的核心:AST是编译器和解释器处理源代码的关键数据结构。在对源代码进行语法分析之后,编译器或解释器会生成AST。接下来,它们可以在AST上进行进一步的分析、优化和代码生成。这使得编译器和解释器能够更高效地处理源代码,为生成可执行程序或执行脚本提供基础。

代码分析:AST在静态代码分析和静态类型检查中起着重要作用。通过分析AST,我们可以检测代码中的潜在错误、不良实践和安全漏洞,从而提高代码质量。

代码转换和优化:编译器、解释器和其他工具(如Babel或Webpack)可以使用AST来进行代码转换和优化。这些工具可以在AST上执行各种操作,如语法转换(例如将ES6+语法转换为ES5语法)、代码压缩、代码拆分和常量传播等。这有助于提高程序的性能和兼容性。

代码生成:基于AST,编译器和解释器可以生成目标代码(例如机器代码、字节码或其他编程语言的代码)。这使得跨平台编译和运行成为可能,例如:将C++代码编译为WebAssembly,以便在Web浏览器中运行。

代码重构和编辑器支持:AST在代码重构和编辑器支持中也起着重要作用。通过分析和操作AST,我们可以实现自动化的代码重构、代码补全、语法高亮、错误检查等功能,从而提高开发者的生产力。

3、AST还能做什么

抽象语法树(AST)在编程语言处理、软件工程和开发工具中发挥着关键作用。除了前面讨论过的用途之外,AST还可以用于以下方面:

代码生成器:可以根据AST生成代码模板和脚手架工具。例如,根据类和方法定义生成REST API的客户端和服务器端实现。

语言转换:通过分析源语言的AST,然后将其转换为目标语言的AST,可以实现源代码到目标代码的转换。例如,将TypeScript代码转换为JavaScript代码。

代码覆盖率分析:通过分析AST,我们可以检测测试用例覆盖的代码范围,从而衡量测试质量和查找潜在的漏洞。

文档生成:AST可以用于提取源代码中的注释、类、方法和属性等信息,从而自动生成API文档。

代码安全性分析:通过分析AST,可以识别不安全的代码模式和潜在的安全漏洞,从而提高软件安全性。

代码审查:AST可以帮助自动化检查代码是否符合团队的编程规范和约定,从而提高代码质量和一致性。

依赖关系分析:通过分析AST,可以识别源代码中的模块、类和函数之间的依赖关系,从而理解代码结构和优化代码组织。

自动补全和代码导航:通过分析AST,集成开发环境(IDE)和代码编辑器可以提供自动补全、代码导航、变量重命名等智能功能,从而提高开发者的生产力。

语言扩展和领域特定语言(DSL):AST可以用于设计和实现领域特定语言,这些语言可以更简洁地表示特定领域的问题和解决方案。例如,通过将DSL转换为目标编程语言的AST,可以生成可执行代码。

三、Python AST

Python AST是Python源代码的抽象语法树表示形式。它是Python编译器在解析源代码时生成的一种数据结构,用于表示源代码的语法结构。

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) --> 控制流程图 --> 字节码

1、Python AST的基本结构

Python AST是由一系列节点(Node)组成的树形结构。每个节点代表了Python源代码中的一个语法结构,例如函数、类、变量、表达式等。每个节点都有一个类型(Type)和一些属性(Attribute),用于描述节点的语法结构和语义信息。

节点可以分类为:

  • 常量节点(Literals)
  • 变量节点(Variables)
  • 表达式节点(Expressions)
  • 声明节点(Statements)
  • 控制流节点(Control flow,if/for/while等)
  • 函数和类的定义节点(Function and class definitions)
  • 异步和等待节点(Async and await)
  • 顶层节点(Top level nodes)

以下是Python AST的一些常见节点类型:

  • Module: 代表整个Python模块。
  • FunctionDef: 代表函数定义。
  • ClassDef: 代表类定义。
  • Name: 代表变量名。
  • Constant: 代表常量。
  • BinOp: 代表二元操作符表达式。

其余的节点类型见:ast --- 抽象语法树 — Python 3.12.1 文档

2、AST模块的基本用法 

在Python中,我们可以使用ast模块提供的parse()函数将源代码解析为抽象语法树对象,并使用walk()方法遍历该对象。

除了ast.dump,有很多dump ast的第三方库,如astunparse, codegen, unparse等。这些第三方库不仅能够以更好的方式展示出ast结构,还能够将ast反向导出python source代码。

import ast
import astpretty

# 解析源代码,获得抽象语法树对象
ast_tree = ast.parse("print('Hello, world!')")
# 遍历抽象语法树对象
for node in ast.walk(ast_tree):
    # print(type(node).__name__)
    print("*"*66)
    astpretty.pprint(node)

以上代码输出内容如下:

Module(
    body=[
        Expr(
            lineno=1,
            col_offset=0,
            end_lineno=1,
            end_col_offset=22,
            value=Call(
                lineno=1,
                col_offset=0,
                end_lineno=1,
                end_col_offset=22,
                func=Name(lineno=1, col_offset=0, end_lineno=1, end_col_offset=5, id='print', ctx=Load()),
                args=[Constant(lineno=1, col_offset=6, end_lineno=1, end_col_offset=21, value='Hello, world!', kind=None)],
                keywords=[],
            ),
        ),
    ],
    type_ignores=[],
)
******************************************************************
Module(
    body=[
        Expr(
            lineno=1,
            col_offset=0,
            end_lineno=1,
            end_col_offset=22,
            value=Call(
                lineno=1,
                col_offset=0,
                end_lineno=1,
                end_col_offset=22,
                func=Name(lineno=1, col_offset=0, end_lineno=1, end_col_offset=5, id='print', ctx=Load()),
                args=[Constant(lineno=1, col_offset=6, end_lineno=1, end_col_offset=21, value='Hello, world!', kind=None)],
                keywords=[],
            ),
        ),
    ],
    type_ignores=[],
)
******************************************************************
Expr(
    lineno=1,
    col_offset=0,
    end_lineno=1,
    end_col_offset=22,
    value=Call(
        lineno=1,
        col_offset=0,
        end_lineno=1,
        end_col_offset=22,
        func=Name(lineno=1, col_offset=0, end_lineno=1, end_col_offset=5, id='print', ctx=Load()),
        args=[Constant(lineno=1, col_offset=6, end_lineno=1, end_col_offset=21, value='Hello, world!', kind=None)],
        keywords=[],
    ),
)
******************************************************************
Call(
    lineno=1,
    col_offset=0,
    end_lineno=1,
    end_col_offset=22,
    func=Name(lineno=1, col_offset=0, end_lineno=1, end_col_offset=5, id='print', ctx=Load()),
    args=[Constant(lineno=1, col_offset=6, end_lineno=1, end_col_offset=21, value='Hello, world!', kind=None)],
    keywords=[],
)
******************************************************************
Name(lineno=1, col_offset=0, end_lineno=1, end_col_offset=5, id='print', ctx=Load())
******************************************************************
Constant(lineno=1, col_offset=6, end_lineno=1, end_col_offset=21, value='Hello, world!', kind=None)
******************************************************************
Load()

 以上内容是抽象语法树中的6个节点,其中,Module表示整个模块,Expr表示一个表达式,Call表示一个函数调用。那么我们可以画出来:

import ast
import ctree
ast_tree = ast.parse("print('Hello, world!')")
ctree.ipython_show_ast(ast_tree)

从语法树中可以看出,该语句加载(Load())了名(Name())为print的函数接口(func),函数传参(args)是值为’Hello, world!’(value)的常量(Constant)。 

C语言分析:

import ast
import ctree
from ctree.transformations import PyBasicConversions

ast_tree = ast.parse("print('Hello, world!')")
# ctree.ipython_show_ast(ast_tree)
t = PyBasicConversions()
tree2 = t.visit(ast_tree)
ctree.ipython_show_ast(tree2)

 

3、使用AST模块进行代码分析

由于AST可以表示源代码的结构,因此,我们可以结合AST模块对Python代码进行语法分析、代码检查、重构等操作。

3.1. 语法分析

我们可以使用AST模块提供的NodeVisitor类来遍历代码并进行分析。NodeVisitor是一个抽象基类,它定义了许多方法,我们只需要重写需要的方法即可。

import ast

class MyVisitor(ast.NodeVisitor):
    def visit_BinOp(self, node):
        print(type(node).__name__)

# 解析源代码,获得抽象语法树对象
tree = ast.parse("a + b")

# 实例化并遍历分析器
visitor = MyVisitor()
visitor.visit(tree)

以上代码定义了一个分析器类MyVisitor,它继承自NodeVisitor并重写了visit_BinOp方法。visit_BinOp方法指在遍历二元运算符节点时被调用,因此可以在该方法中进行具体的分析。

3.2. 代码检查

AST模块提供了许多内置函数和类,可以用于检查代码是否符合某些规范。

import ast

# 检查函数名是否符合规范
def check_func_name(node):
    func_name = node.name
    if not func_name.startswith("test_"):
        print(f"函数名{func_name}不符合规范!")

# 解析源代码,获得抽象语法树对象
tree = ast.parse("def test_add(a, b):\n    return a + b\n\ndef sub(a, b):\n    return a - b")

# 遍历抽象语法树对象
for node in ast.walk(tree):
    if isinstance(node, ast.FunctionDef):
        check_func_name(node)

以上代码定义了一个检查器函数check_func_name,它判断函数名是否以"test_"开头。在遍历抽象语法树时,如果找到了函数节点,就可以调用check_func_name进行检查。

3.3. 代码重构

代码重构是指对已有代码的结构和实现进行修改以改进代码的质量和维护性。AST模块可以帮助我们对Python代码进行重构,例如,将代码中的print语句替换为logging模块。

import ast

# 重构代码,将所有的print语句替换为调用logging模块
class MyTransformer(ast.NodeTransformer):
    def visit_Print(self, node):
        print_node = ast.Name(id="logging.info", ctx=ast.Load())
        args_node = [ast.Str(s="Print statement at line {0}".format(node.lineno))]
        args_node += node.values
        return ast.Expr(value=ast.Call(func=print_node, args=args_node, keywords=[]))

# 解析源代码,获得抽象语法树对象
tree = ast.parse("print('Hello, world!')\n")

# 将抽象语法树对象重构为新的语法树对象
my_transformer = MyTransformer()
new_tree = my_transformer.visit(tree)

# 使用astunparse将语法树源代码还原为字符串
import astunparse
print(astunparse.unparse(new_tree))

以上代码定义了一个重构器类MyTransformer,它继承自NodeTransformer并重写了visit_Print方法。visit_Print方法指在遍历print语句节点时被调用,可以在该方法中进行替换操作。


参考:

你知道什么是AST语法树嘛?你真的了解AST语法树嘛?读到最后你将对AST语法树有新的认识! - 知乎

ast --- 抽象语法树 — Python 3.12.1 文档

Python Ast抽象语法树的介绍及应用详解 - Python技术站

https://www.cnblogs.com/qiulinzhang/p/14258626.html

Python中ast模块是什么?_笔记大全_设计学院

【python】ast模块介绍和使用_import ast-CSDN博客

不要再手动批量替换了,使用python AST模块批量替换_Python_阿呆_InfoQ写作社区

https://www.cnblogs.com/yssjun/p/10069199.html

python语法树可视化_mob649e815b1a71的技术博客_51CTO博客

Python中ast模块是什么?_笔记大全_设计学院

https://www.cnblogs.com/qiulinzhang/p/14258626.html

python 可视化AST、CFG学习_python显示ast树形状-CSDN博客

【python】ast模块介绍和使用_import ast-CSDN博客

Using IPython for AST Visualization — ctree alpha documentation 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1384275.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

<软考高项备考>《论文专题 - 65 质量管理(4) 》

4 过程3-管理质量 4.1 问题 4W1H过程做什么为了评估绩效,确保项目输出完整、正确且满足客户期望,而监督和记录质量管理活动执行结果的过程作用:①核实项目可交付成果和工作已经达到主要干系人的质量要求,可供最终验收;②确定项目…

class_4:car类

#include <iostream> using namespace std; class Car{ public://成员数据string color; //颜色string brand; //品牌string type; //车型int year; //年限//其实也是成员数据&#xff0c;指针变量&#xff0c;指向函数的变量&#xff0c;并非真正的成员函数void (*…

剪映国际版,免费无限制使用

随着抖音的爆火短视频的崛起&#xff0c;相信每一个人都感受到了短视频快节奏下的生活洪流。 现如今每个人都能成为自己生活的记录者&#xff0c;每一个人都有掌握着剪辑的基本技能。而剪映就是很多人都会使用的剪辑软件。 相对于PR、AE等剪辑软件来说&#xff0c;作为一款国…

读《Open-Vocabulary Video Anomaly Detection》

2023 西北工业大学和新大 引言 视频异常检测(VAD)旨在检测不符合预期模式的异常事件&#xff0c;由于其在智能视频监控和视频内容审查等应用前景广阔&#xff0c;已成为学术界和工业界日益关注的问题。通过几年蓬勃发展&#xff0c;VAD 在许多不断涌现的工作中取得了重大进展。…

spring-mvc(1):Hello World

虽然目前大多数都是使用springboot来开发java程序&#xff0c;或者使用其来为其他端提供接口&#xff0c;而为其他端提供接口&#xff0c;这些功能都是依靠springmvc实现的&#xff0c;所以有必要学习一下spring-mvc&#xff0c;这样才能更好的学习springboot。 一&#xff0c…

好物周刊#36:程序员简历

村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. SmartDNS 一个运行在本地的 DNS 服务器&#xff0c;它接受来自本地客户端的 DNS 查询请求&#xff0c;然后从多个上游 DNS 服务器获取 DNS 查询…

陶瓷碗口缺口检测-图像分割

图像分割 由于对碗口进行缺口检测&#xff0c;因此只需要碗口的边界信息。得到陶瓷碗区域填充后的图像&#xff0c;对图像进行边缘检测。这是属于图像分割中的内容&#xff0c;在图像的边缘中&#xff0c;可以利用导数算子对数字图像求差分&#xff0c;将边缘提取出来。 本案…

案例:新闻数据加载

文章目录 介绍相关概念相关权限约束与限制完整示例 代码结构解读构建主界面数据请求下拉刷新总结 介绍 本篇Codelab是基于ArkTS的声明式开发范式实现的样例&#xff0c;主要介绍了数据请求和touch事件的使用。包含以下功能&#xff1a; 数据请求。列表下拉刷新。列表上拉加载…

基于面向对象,C++实现双链表

双链表同单链表类似&#xff0c;由一个值和两个指针组成 Node.h节点头文件 #pragma once class Node { public:int value;Node* prev;Node* next;Node(int value);~Node(); };Node.cpp节点源文件 #include "Node.h"Node::Node(int value) {this->value value…

Python-高阶函数

在Python中&#xff0c;高阶函数是指能够接收函数作为参数&#xff0c;或者能够返回函数的函数。这种特性使得函数在Python中可以被灵活地传递和使用。以下是一些关于Python高阶函数的详细解释&#xff1a; 函数作为参数&#xff1a; 高阶函数可以接收其他函数作为参数。这样的…

C语言 - 最简单,最易懂的指针、引用讲解

一、变量、地址、变量值 二、直接上代码&#xff0c;一边看上图&#xff0c;一边讲解 #include <stdio.h>struct Hello {int a;int b; };int main() {struct Hello h;h.a 10;h.b 20;struct Hello *hp;hp &h;printf("1: h的地址是%d&#xff0c;hp地址是%d \…

89.乐理基础-记号篇-省略记号-震音、音型与小节反复

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;88.乐理基础-记号篇-反复记号&#xff08;二&#xff09;D.C.、D.S.、Fine、Coda-CSDN博客 省略记号总结图&#xff1a;有些素材会把它们归纳到反复记号里&#xff0c;因为它们也涉及到 重复、反复的概念&#xff…

Open3D 两片点云的最小/最大距离(23)

Open3D 两片点云的最小/最大距离(23) 一、效果展示二、使用步骤1.代码三、cloudcompare量距小工具一、效果展示 算法与实际量测的结果保持一致,输出最近距离和对应点 二、使用步骤 1.代码 import open3d as o3d import numpy as np# 读取点云数据 cloud_2 = o3d.io.re…

查询和结果处理的Java代码

match_all查询&#xff1a; //查询所有文档 match_all查询Testvoid testMatchAll() throws IOException {// 1.准备RequestSearchRequest request new SearchRequest("hotel");// 2.准备DSLrequest.source().query(QueryBuilders.matchAllQuery());// 3.发送请求Sea…

Linux Centos7静默安装(非图形安装)Oracle RAC 11gR2(Oracle RAC 11.2.0.4)

Oracle RAC (全称Oracle Real Application Clusters &#xff09;静默安装&#xff08;非图形安装&#xff09;教程。 由于这篇文章花费了我太多时间&#xff0c;设置了仅粉丝可见&#xff0c;见谅。 环境说明&#xff1a; 虚拟机软件&#xff1a;VMware Workstation 16 Pro…

Spring Boot - Application Events 的发布顺序_ApplicationPreparedEvent

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c;它允许在 Spring 应用程序中发布和监听事件。这种机制的主要目的是为了实现解耦&#…

Android基于Matrix绘制PaintDrawable设置BitmapShader,以手指触点为中心显示原图像圆图,Kotlin(3)

Android基于Matrix绘制PaintDrawable设置BitmapShader&#xff0c;以手指触点为中心显示原图像圆图&#xff0c;Kotlin&#xff08;3&#xff09; 在 Android基于Matrix绘制PaintDrawable设置BitmapShader&#xff0c;以手指触点为中心显示原图像圆图&#xff0c;Kotlin&#…

网络地图服务(WMS)详解

文章目录 1.概述2.GetCapabilities3.GetMap4.GetFeatureInfo 阅读本文之前可参考前文&#xff1a;《地图服务器GeoServer的安装与配置》与《GeoServer发布地图服务&#xff08;WMS、WFS&#xff09;》。 1.概述 经过前文的介绍&#xff0c;相信我们对WMS/WFS服务已经有了一个非…

基于Token认证的登录功能实现

Session 认证和 Token 认证过滤器和拦截器 上篇文章我们讲到了过滤器和拦截器理论知识以及 SpringBoot 集成过滤器和拦截器&#xff0c;本篇文章我们使用过滤器和拦截器去实现基于 Token 认证的登录功能。 一、登录校验 Filter 实现 1.1、Filter 校验流程图 获得请求 url。判…

Express 应用生成器(脚手架)的安装与使用

1、简介 自动生成一个express搭建的项目结构 官网&#xff1a;Express 应用生成器 2&#xff0c;使用 2.1全局安装&#xff0c;使用管理员打开命令窗口 2.2、安装express # 全局安装express npm install -g express # 全局安装express脚手架 npm install -g express-gene…