当前位置: 首页 > news >正文

Python 高手编程系列四百三十四:抽象语法树

返回
26/100
2301_77888392

Python 语法首先被转换成抽象语法树(Abstract Syntax Tree,AST),然后才被编译成
字节码。这是对源代码抽象语法结构的一种树状表示。利用内置的 ast 模块,可以得到对
Python 语法的处理过程。利用带有 ast.PyCF_ONLY_AST 标记的 compile()函数或者利
用 ast.parse()帮助函数,可以创建 Python 代码的原始 AST。逆向直接转换却没有那么
简单,没有用于完成这项功能的内置函数。不过有些项目(例如 PyPy)可以完成这项任务。
ast 模块提供了一些帮助函数,可以用于处理 AST,如下所示:

tree = ast.parse('def hello_world(): print(“hello world!”)')
tree
<
ast.Module object at 0x00000000038E9588>
ast.dump(tree)
"Module(
body=[
FunctionDef(
name='hello
world’,
args=arguments(
args=[],
vararg=None,
kwonlyargs=[],
kw
defaults=[],
kwarg=None,
defaults=[]
),
body=[
Expr(
value=Call(
func=Name(id=‘print’, ctx=Load()),
args=[Str(s=‘hello world!’)],
keywords=[]
)
)
],
decorator
_list=[],
returns=None
)
]
)"
在上一个例子中,对 ast.dump()的输出做了重新格式化,以提高其可读性,并且更
好地展示 AST 的树状结构。在传递给 compile()调用之前,可以对 AST 进行修改,知道
这一点很重要。例如,新的语法节点可用于额外的测量,例如计算测试覆盖率。也可以修
改现有代码树,以便向现有语法中添加新的语义。MacroPy 项目(https://github.com/lihaoyi/
macropy)就用到了这样的技术,利用已经存在的语法向 Python 中添加语法宏,也可以用纯人工的方式创建 AST,不需要解析任何源代码。这样 Python 程序员就能够
为自定义的领域特定语言创建 Python 字节码,甚至在 Python VM 之上完全实现另一种现有
的编程语言。
导入钩子
利用 MacroPy 的能力修改原始 AST,并不像使用 import macropy.activate 语句
那样简单,如果它不能以某种方式覆写 Python 的导入行为的话。幸运的是,Python 提供了
利用两种导入钩子(import hook)来拦截导入的方法。
• 元钩子(meta hook):它在任何其他 import 处理之前被调用。利用元钩子,你可以覆写 sys.path 的处理方式,甚至是冻结模块(frozen module)和内置模块。
为了添加新的元钩子,必须向 sys.meta_path 列表中添加新的元路径查找器
(meta path finder)对象。
• 导入路径钩子(import path hook):它是作为 sys.path 处理的一部分被调用的。
如果遇到了与给定钩子相关联的路径项,则使用这种钩子。通过使用新的路径查找
器(path finder)对象扩展 sys.path_hooks 列表来添加导入路径钩子。
路径查找器和元路径查找器的实现细节在 Python 官方文档中都有详细说明(https://docs.
python.org/3/reference/import.html)。如果你想要在这个层面上处理导入问题,那么官方文档
应该是你的首选资料。这是因为 Python 的导入机制相当复杂,任何尝试用几个段落进行总
结的方法最终不可避免会失败。你可以将本节当作这些可能做法的笔记,也可以当作更详
细资料的参考。
使用代码生成模式的项目
很难找到一个真正可用的库的实现,它依赖代码生成模式,而又不仅是一项实验或简
单的概念证明。造成这种情况的原因是显而易见的,如下所示。
• 对 exec()和 eval()函数必要的担心,因为不负责任的使用可能会造成真正的灾难。
• 成功的代码生成非常困难,因为它需要对语言特性的深入理解和优异的通用编程技能。
尽管有这些困难,但仍有一些项目成功地应用了这种方法,或者提高了性能,或者实
现了其他方法无法实现的事情。
(1)falcon 的编译路由器
falcon 是一个极简的 Python WSGI Web 框架,用于构建快速又轻量级的 API。它极力
推崇目前在Web上非常流行的REST架构风格。它是对其他大型框架(如Django或Pyramid)
的很好的替代。对于其他致力于精简的微框架(如 Flask、Bottle 和 Web2py)而言,它也
是一个强大的竞争对手。
其特性之一就是非常简单的路由机制。它不像 Django 的 urlconf 提供的路由那样复
杂,也没有提供那么多的功能,但在大多数情况下,对于遵照 REST 架构设计的 API 都是
够用的。关于 falcon 的路由,最有趣的是实际的路由器是利用路由列表生成的代码来实现
的,这些路由列表被提供给定义 API 配置的对象。这种方法使路由的速度很快。
思考下面这个非常简短的 API 示例(来自于 falcon 的网上文档):

sample.py

import falcon
import json
class QuoteResource:
def on_get(self, req, resp):
“”“Handles GET requests”“”
quote = {
‘quote’: ‘I’ve always been more interested in ’
‘the future than in the past.’,
‘author’: ‘Grace Hopper’
}
resp.body = json.dumps(quote)
api = falcon.API()
api.add_ _route(’/quote’, QuoteResource())
加粗的代码是对 api.add_route()方法的调用,简而言之,就是更新整个动态生成
的路由器代码树,利用 compile()进行编译,并利用 eval()生成新的路由查找函数。观
察 api._router._find()函数的__code__属性,可以发现它是从字符串中生成的,每
次调用 api.add_route()都会发生如下改变:

api._router._find. _code __
<code object find at 0x00000000033C29C0, file “”, line 1>
api.add
route(‘/none’, None)
api.
router._find. __code __
<code object find at 0x00000000033C2810, file “”, line 1>

Python 语法首先被转换成抽象语法树(Abstract Syntax Tree,AST),然后才被编译成
字节码。这是对源代码抽象语法结构的一种树状表示。利用内置的 ast 模块,可以得到对
Python 语法的处理过程。利用带有 ast.PyCF_ONLY_AST 标记的 compile()函数或者利
用 ast.parse()帮助函数,可以创建 Python 代码的原始 AST。逆向直接转换却没有那么
简单,没有用于完成这项功能的内置函数。不过有些项目(例如 PyPy)可以完成这项任务。
ast 模块提供了一些帮助函数,可以用于处理 AST,如下所示:

tree = ast.parse('def hello_ world(): print(“hello world!”)') tree < ast.Module object at 0x00000000038E9588> ast.dump(tree) "Module( body=[ FunctionDef( name='hello world’, args=arguments( args=[], vararg=None, kwonlyargs=[], kw defaults=[], kwarg=None, defaults=[] ), body=[ Expr( value=Call( func=Name(id=‘print’, ctx=Load()), args=[Str(s=‘hello world!’)], keywords=[] ) ) ], decorator _list=[], returns=None ) ] )" 在上一个例子中,对 ast.dump()的输出做了重新格式化,以提高其可读性,并且更 好地展示 AST 的树状结构。在传递给 compile()调用之前,可以对 AST 进行修改,知道 这一点很重要。例如,新的语法节点可用于额外的测量,例如计算测试覆盖率。也可以修 改现有代码树,以便向现有语法中添加新的语义。MacroPy 项目(https://github.com/lihaoyi/ macropy)就用到了这样的技术,利用已经存在的语法向 Python 中添加语法宏,也可以用纯人工的方式创建 AST,不需要解析任何源代码。这样 Python 程序员就能够 为自定义的领域特定语言创建 Python 字节码,甚至在 Python VM 之上完全实现另一种现有 的编程语言。 导入钩子 利用 MacroPy 的能力修改原始 AST,并不像使用 import macropy.activate 语句 那样简单,如果它不能以某种方式覆写 Python 的导入行为的话。幸运的是,Python 提供了 利用两种导入钩子(import hook)来拦截导入的方法。 • 元钩子(meta hook):它在任何其他 import 处理之前被调用。利用元钩子,你可以覆写 sys.path 的处理方式,甚至是冻结模块(frozen module)和内置模块。 为了添加新的元钩子,必须向 sys.meta_path 列表中添加新的元路径查找器 (meta path finder)对象。 • 导入路径钩子(import path hook):它是作为 sys.path 处理的一部分被调用的。 如果遇到了与给定钩子相关联的路径项,则使用这种钩子。通过使用新的路径查找 器(path finder)对象扩展 sys.path_hooks 列表来添加导入路径钩子。 路径查找器和元路径查找器的实现细节在 Python 官方文档中都有详细说明(https://docs. python.org/3/reference/import.html)。如果你想要在这个层面上处理导入问题,那么官方文档 应该是你的首选资料。这是因为 Python 的导入机制相当复杂,任何尝试用几个段落进行总 结的方法最终不可避免会失败。你可以将本节当作这些可能做法的笔记,也可以当作更详 细资料的参考。 使用代码生成模式的项目 很难找到一个真正可用的库的实现,它依赖代码生成模式,而又不仅是一项实验或简 单的概念证明。造成这种情况的原因是显而易见的,如下所示。 • 对 exec()和 eval()函数必要的担心,因为不负责任的使用可能会造成真正的灾难。 • 成功的代码生成非常困难,因为它需要对语言特性的深入理解和优异的通用编程技能。 尽管有这些困难,但仍有一些项目成功地应用了这种方法,或者提高了性能,或者实 现了其他方法无法实现的事情。 (1)falcon 的编译路由器 falcon 是一个极简的 Python WSGI Web 框架,用于构建快速又轻量级的 API。它极力 推崇目前在Web上非常流行的REST架构风格。它是对其他大型框架(如Django或Pyramid) 的很好的替代。对于其他致力于精简的微框架(如 Flask、Bottle 和 Web2py)而言,它也 是一个强大的竞争对手。 其特性之一就是非常简单的路由机制。它不像 Django 的 urlconf 提供的路由那样复 杂,也没有提供那么多的功能,但在大多数情况下,对于遵照 REST 架构设计的 API 都是 够用的。关于 falcon 的路由,最有趣的是实际的路由器是利用路由列表生成的代码来实现 的,这些路由列表被提供给定义 API 配置的对象。这种方法使路由的速度很快。 思考下面这个非常简短的 API 示例(来自于 falcon 的网上文档):

sample.py

import falcon
import json
class QuoteResource:
def on_get(self, req, resp):
“”“Handles GET requests”“”
quote = {
‘quote’: ‘I’ve always been more interested in ’
‘the future than in the past.’,
‘author’: ‘Grace Hopper’
}
resp.body = json.dumps(quote)
api = falcon.API()
api.add_ _route(’/qu利用 eval()生成新的路由查找函数。观
察 api._router._find()函数的__code__属性,可以发现它是从字符串中生成的,每
次调用 api.add_route()都会发生如下改变:

api._ router. _find. _code __ <code object find at 0x00000000033C29C0, file “”, line 1> api.add route(‘/none’, None) api. router. _find. __code __ <code object find at 0x00000000033C2810, file “”, line 1>

Markdown 已选中 2787 字数 100 行数 当前行 100, 当前列 0
HTML 2735 字数 98 段落

http://www.jsqmd.com/news/1014289/

相关文章:

  • 别再被厂商的MTBF数字忽悠了!聊聊硬盘、服务器真实寿命与选购避坑
  • AsrTools:智能语音转文字工具,三步完成音频字幕转换
  • 2026年6月最新版邢台正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一休咨询
  • Minecraft基岩版多版本管理终极指南:解锁无限游戏体验的5个关键技巧
  • 深度解析trackerslist:BitTorrent跟踪服务器架构与技术实现
  • 采购工业测温液位仪表去哪找靠谱厂家看这篇就够了(2026年) - 品牌推荐大师1
  • BongoCat互动桌面宠物:3步掌握Live2D模型自定义开发终极指南
  • 如何3步永久掌控你的微信数据管理:免费开源工具终极指南
  • LeetDown终极指南:3步让老旧iPhone/iPad重获新生
  • 终极防撤回解决方案:PC版微信QQ消息永久保存完全指南
  • 【效率革命】3步实现跨平台Boot Camp驱动自动化部署
  • 深度对比:WPS AI与微软Copilot在办公场景的初体验与未来猜想
  • 2026年北京学员领取众智商学院试听课和资料前怎么确认课程信息 - 众智商学院官方
  • 终极免费资源嗅探:3分钟掌握猫抓Cat-Catch浏览器扩展的完整使用指南
  • 如何快速掌握AsrTools:面向新手的终极语音转文字工具完整指南
  • 2026年6月最新版铜陵正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一休咨询
  • 5分钟快速上手:M3U8视频下载器终极指南
  • 从模块化设计到用户体验:foobox-cn如何重构专业音乐播放器的界面范式
  • C++高并发场景选型指南:除了concurrentqueue,还有哪些无锁队列值得一试?
  • MPC8544E安全引擎加密通道配置与实战:从原理到性能优化
  • 2026年6月最新版徐州正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一休咨询
  • 无穷大电源系统三相短路仿真3(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 2026年6月最新版通辽正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一休咨询
  • 2026亚太科技转型向EMBA中立测评与理性选型指南
  • AI大模型就业:普通程序员如何抓住下一轮机会:线上排查时才会暴露的细节
  • 2026年6月最新版绥化正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一休咨询
  • 永久保存微信聊天记录的终极方案:WeChatMsg免费开源工具完整指南
  • 如何在macOS上安装IINA播放器:免费开源视频播放器的终极指南
  • Prometheus高可用选型指南:多实例、远程存储、联邦还是Thanos?一次讲清你的生产环境该怎么搭
  • BetterGI开源游戏自动化工具完整使用教程:3步实现智能游戏辅助