未定义的Hy宏执行断言报AssertionError而非NameError,是否为Bug?
关于Hy中未定义宏调用的报错差异问题
先看这段注释掉宏定义的Hy代码:
(eval-and-compile (import os hy)) (eval-and-compile (import pathlib [Path])) ; (defmacro with-cwd [dir #* body] ; (setv cwd (hy.gensym)) ; `(let [ ~cwd (.cwd Path) ] ; (try (.chdir os ~dir) ; ~@body ; (finally (.chdir os ~cwd))))) (setv cookies (/ (.cwd Path) "cookies")) ; 此调用触发`AssertionError' (with-cwd cookies (assert (= (.cwd Path) cookies))) ; 此调用触发`NameError' (with-cwd cookies (.cwd Path))
调用未定义的with-cwd时出现两种不同报错:第一个调用触发AssertionError,第二个触发NameError,你原本预期第一个也会触发NameError,疑惑这是Bug还是对执行顺序的理解偏差。
原因分析
这不是Bug,核心在于Hy的宏编译特性和assert的特殊形式优先级:
- 宏的编译时特性:Hy的宏是编译阶段展开的,未定义的宏调用不会被编译器处理,会原封不动传递给Python解释器。
assert是特殊形式:和普通函数不同,assert的内部表达式会被优先编译执行。第一个调用中,(= (.cwd Path) cookies)会先被执行——此时工作目录并未切换(with-cwd宏没展开,切换逻辑根本没执行),所以判断结果为假,直接触发AssertionError。这个报错发生在Python尝试处理断言时,还没轮到解析外层的with-cwd符号,因此不会出现NameError。- 第二个调用的逻辑:
(with-cwd cookies (.cwd Path))没有特殊形式嵌套,Python解释器会直接把with-cwd当作函数名,但这个符号从未定义,所以抛出NameError。
类似地,任何依赖未定义宏的代码,若嵌套了特殊形式,都可能因特殊形式的优先执行提前报错,掩盖宏未定义的问题。
内容的提问来源于stack exchange,提问作者syvlorg
相关产品推荐
相关产品推荐

