【Python程序开发系列】一文带你了解Python抽象语法树(案例分析)

发布时间:2024年01月03日

这是Python程序开发系列原创文章,我的第189篇原创文章。

一、什么是抽象语法树

? ? ? ?在传统的编译语言的流程中,程序的一段源代码在执行之前会经历三个步骤,统称为“编译”:

  • 分词/词法分析
    这个过程会将由字符组成的字符串分解成有意义的代码块,这些代码块统称为词法单元(token)。举个例子: let a = 1,这段程序通常会被分解成为下面这些词法单元:let 、a、=、1、 ;空格是否被当成此法单元,取决于空格在这门语言中的意义。

  • 解析/语法分析
    这个过程是将词法单元流转换成一个由元素嵌套所组成的代表了程序语法结构的树,这个树被称为"抽象语法树"(abstract syntax code,AST)。

  • 代码生成
    将AST转换成可执行代码的过程被称为代码生成。

????? ?抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构,之所以说是抽象的,抽象表示把代码进行了结构化的转化,转化为一种数据结构。这种数据结构其实就是一个大的json对象,json我们都熟悉,他就像一颗枝繁叶茂的树。有树根,有树干,有树枝,有树叶,无论多小多大,都是一棵完整的树。简单理解,抽象语法树就是把我们写的代码按照一定的规则转换成一种树形结构。

二、Python抽象语法树

? ?? ??Python的抽象语法树是一种非常强大的特性,允许开发者在运行时检查、修改甚至生成Python代码。抽象语法树是源代码的树形表示,每个节点都代表语言的一部分,比如表达式、语句或者是字面量。

? ? ? ?首先, 我们要知道python代码是如何执行的,python作为一种解释性语言,是不用编译的,python源码会被解析来一个抽象语法树AST,最终生成字节码,然后pyhon解释器会执行这个字节码,整个流程如下:

? ? ? ?源代码解析?--> 解析树 -->?抽象语法树(AST)?--> 控制流程图 -->?字节码

????? ?AST作用在Python代码的语法被解析后,被编译成字节码之前。当Python代码执行之前,它会被编译成一个中间形式,这就是抽象语法树。这个树结构定义了代码的语法结构,但去掉了无关紧要的信息(如空格、注释等)。

使用AST的场景:
  • 代码分析:?可以使用AST来理解和分析代码结构。

  • 代码转换:?通过修改AST,可以实现代码重构或代码风格的转换。

  • 安全分析:?审查代码中可能的安全漏洞。

  • 自动生成代码:?利用AST生成新的代码。

三、案例分析

3.1 定义一个函数

def add(a, b):
    return a + b

定义函数的结构,实现两个数的相加求和。

3.2 生成AST

import ast
# 获取函数的源代码
source = '''
def add(a, b):
    return a + b
'''
# 解析源代码为AST
parsed_source = ast.parse(source)
print(parsed_source)

生成一个AST对象:

图片

3.3 检查AST

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

函数的AST结构如下:

图片

3.4 遍历AST

class FunctionVisitor(ast.NodeVisitor):
    def visit_FunctionDef(self, node):
        print(f"Function name: {node.name}")
        self.generic_visit(node)

visitor = FunctionVisitor()
visitor.visit(parsed_source)

输出add,因为add是在我们的代码中定义的函数。

3.5 修改AST

class RewriteAdd(ast.NodeTransformer):
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Add):
            return ast.BinOp(left=node.left, op=ast.Sub(), right=node.right)
        return self.generic_visit(node)

modified_tree = RewriteAdd().visit(parsed_source)
# 修复AST节点并添加缺失的行号信息
ast.fix_missing_locations(modified_tree)
exec(compile(modified_tree, filename="<ast>", mode="exec"))
print(add(3, 2))

修改后,add函数实际上会进行减法运算,输出结果为1。

四、小结

????????本文主要总结了关于Python抽象语法树的一些概念和简单的用法需要源码的小伙伴可以关注底部公众号添加作者微信

作者简介:

读研期间发表6篇SCI数据挖掘相关论文,现在某研究院从事数据算法相关科研工作,结合自身科研实践经历不定期分享关于Python、机器学习、深度学习、人工智能系列基础知识与应用案例。致力于只做原创,以最简单的方式理解和学习,关注我一起交流成长。

文章来源:https://blog.csdn.net/sinat_41858359/article/details/135354850
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。