当前位置:首页>python>这个霸总会Python(10/14)- “`ast` 破土”

这个霸总会Python(10/14)- “`ast` 破土”

  • 2026-10-11 07:38:50
这个霸总会Python(10/14)- “`ast` 破土”

霸都老科学岛,地下二层。

废弃的机房亮起一盏应急灯。三面机架空空荡荡,墙上还贴着2008年的机房巡检表——泛黄、落满灰。空气里混着臭氧和铁锈味,像一台快要报废的老式服务器。

「这是我爸建神码之前待的地方。」程思语拍掉ThinkPad上的灰,「零几年合肥还叫霸都的时候,他在这儿写第一版交易引擎。」

陈默扫了一圈。墙角线槽里还挂着十年前的六类网线,像一条条干枯的蛇。

「他肯定想不到,有一天他女儿会拿他起家的地方,造他施毒的解药。」

程思语没接话。她把内网虚拟机接入机房里一个布满灰尘的服务器端口——壳公司租的专线,物理层独立,绕过程泰来的一切监控。

屏幕亮了。

陈默打开终端,敲下第一行:

```python

import ast

```

手指悬在回车键上,停了半秒。

「怎么了?」程思语问。

「上一次敲这个东西,还是用来画Python语法树玩。」陈默按下回车,「这一次,要拿它当手术刀。」

光标下,代码逐行展开。

```python

sample = """

try:

    process(data)

except ValueError as e:

    alert(e)

    raise

"""

tree = ast.parse(sample)

print(ast.dump(tree, indent=2))

```

屏幕上弹出一棵语法树——从 `Module` 根节点,到 `Try` 节点,到 `ExceptHandler`,再到 `Raise`。每一层都干干净净,像是编译器没被污染之前的纯净蓝图。

程思语盯着屏幕:「所以AST层面是干净的——那字节码的毒,是在编译那一步下的?」

「对。」陈默敲下第二段代码:

```python

compiled = compile(sample, '<验证>', 'exec')

```

然后打开 `dis`。

```python

import dis

dis.dis(compiled)

```

屏幕显示 `RAISE_VARARGS` 指令——完好无损,像刚从工厂出来的零件。

程思语长长呼出一口气。

「这一行 `raise`——」她说,「我追了三个多月。」

「不是`raise`的问题。」陈默把 `ast.dump` 的输出拉大,「是验证的问题。我们怎么让全世界相信,任意一段Python代码,它的异常处理是真实的?」

他敲了一段新的代码——这一次,不再是从字符串生成AST,而是手写AST节点。

```python

# 手动构造一个保证 raise 的代码块

raise_node = ast.Raise()

handler = ast.ExceptHandler(

    type=ast.Name(id='Exception', ctx=ast.Load()),

    name='e',

    body=[raise_node]

)

try_node = ast.Try(

    body=[ast.Raise()],

    handlers=[handler],

    orelse=[],

    finalbody=[]

)

module = ast.Module(body=[try_node], type_ignores=[])

ast.fix_missing_locations(module)

clean_code = compile(module, '<freedom>', 'exec')

exec(clean_code)

```

终端立刻输出:

```

Traceback (most recent call last):

  File "<freedom>", line 1, in <module>

    raise Exception()

Exception

```

程思语盯着那三行Traceback,眼眶红了一瞬。

「这是我见过最漂亮的Traceback。」

陈默没说话。他盯着屏幕上的异常堆栈——一个真正被抛出、被传播、没有被任何人吞掉的异常。

从第1章被裁,到第9章发现字节码投毒——他终于亲手编译了一段无法被篡改的 `raise`。

「但这还不够。」陈默把椅子往后一推,「手动构造AST不是出路。我们需要一个工具——」

「——能从任意Python代码生成可信字节码的编译器?」程思语接上。

「不。是验证器。」陈默打开一个新的文件,敲下几行骨架:

```python

class RaiseGuard:

    """编译验证器:确保每一条路径上的 raise 都真实存在。"""

    def __init__(self):

        self._trusted_compile = compile

```

「先做验证,再做生成。先保证能看到毒,再保证不中毒。」

程思语的手机震了一下。她低头看,脸色微变。

「怎么?」

「我爸的人开始查壳公司的IP了。我们大概——还有三天。」

窗外,科学岛的夕阳把锈蚀的机架染成金色。三面空机架,一台ThinkPad,两个被全行业追捕的人,和一个刚写了两行的 `RaiseGuard` 类。

陈默把窗口最小化。

「三天够写一个编译器。」

程思语没笑。

「如果不够呢?」

「那至少够让Traceback被全世界看见。」

他敲下第三行代码——为 `RaiseGuard` 加上第一个函数。

屏幕的光在灰暗的机房里,是唯一还亮着的东西。

最新文章

随机文章