1. 引言:Python 开发者的“缩进噩梦”
想象一下,你接手了一个古老的 Python 项目,Tech Lead 让你把所有的 unittest 断言风格: assert foo == bar 全部迁移成: self.assertEqual(foo, bar)
你打开 IDE,准备写一个正则表达式。 突然你意识到:
缩进地狱:Python 是缩进敏感的,正则很难处理多层嵌套里的缩进。
多行问题:如果 assert 的内容太长换行了怎么办?
上下文:你只想改 class Test(unittest.TestCase) 里的代码,不想误伤普通的 assert 语句。
以前,你可能需要花半天时间去研究 Python 自带的 ast 库,写一个 100 行的 NodeTransformer。 现在,用 ast-grep,你只需要 30 秒。
2. 概念拆解:它懂 Python 的语法
生活类比:Word 查找替换 vs. 智能改卷助手
正则表达式 就像 Word 里的“查找替换”。它只认识字母,根本不在乎你是在函数里,还是在注释里,更不懂 Python 的缩进规则。
ast-grep 就像一位懂 Python 语法的助教。你告诉它:“把所有测试用例里的‘相等断言’改一下写法”。它能看懂哪里是函数体,哪里是装饰器,哪里是换行续行。
核心优势:
无视缩进:你写的 Pattern 不需要关心缩进,ast-grep 会自动适配目标代码的缩进层级。
智能匹配:它能区分字符串里的 assert 和真正的关键字 assert。
3. 动手实战:从 print 到 logging
我们先看一个经典场景:把调试用的 print 换成生产环境的 logger.info。
第一步:安装
ast-grep 既提供了命令行工具,也提供了 Python 绑定(可以直接在 Python 脚本里调用)。
Bash
# 安装命令行工具 (推荐作为入口)
pip install ast-grep-cli
# 或者安装 Python 绑定库 (用于写复杂脚本)
pip install ast-grep
第二步:实战演练 (CLI 方式)
创建一个 legacy.py:
Python
def process_data(data):
# 这里的 print 应该被替换
print(f"Processing {data}")
if not data:
# 即使有缩进,也能完美处理
print("Error: No data")
return
在终端运行:
Bash
sg run --lang python \
--pattern 'print($MSG)' \
--rewrite 'logger.info($MSG)' \
legacy.py
见证奇迹: legacy.py 瞬间变为:
Python
def process_data(data):
# 这里的 print 应该被替换
logger.info(f"Processing {data}")
if not data:
# 即使有缩进,也能完美处理
logger.info("Error: No data")
return
注意:它不仅替换了文本,还完美保留了第二行 logger 的缩进!
4. 进阶深潜:用 Python 脚本操作 Python 代码
CLI 适合简单替换,但如果你需要复杂的逻辑(比如:只替换函数名为 test_ 开头的函数里的断言),这时候 Python 绑定 (pip install ast-grep) 就派上用场了。
场景:迁移 Unittest 断言
我们需要把 assert a == b 变成 self.assertEqual(a, b),但前提是这两个变量必须是简单的变量,不能是复杂的函数调用。
如何三行代码实现Python代码批量重构,无需ast模块?
摘要:1. 引言:Python 开发者的“缩进噩梦” 想象一下,你接手了一个古老的 Python 项目,Tech Lead 让你把所有的 unittest 断言风格: assert foo == bar 全部迁移成: self.assertEqu
